- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章详解C++编程中对二进制文件的读写操作由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
二进制文件不是以ASCII代码存放数据的,它将内存中数据存储形式不加转换地传送到磁盘文件,因此它又称为内存数据的映像文件。因为文件中的信息不是字符数据,而是字节中的二进制形式的信息,因此它又称为字节文件.
对二进制文件的操作也需要先打开文件,用完后要关闭文件。在打开时要用ios::binary指定为以二进制形式传送和存储。二进制文件除了可以作为输入文件或输出文件外,还可以是既能输入又能输出的文件。这是和ASCII文件不同的地方。 用成员函数read和write读写二进制文件 。
对二进制文件的读写主要用istream类的成员函数read和write来实现。这两个成员函数的原型为 。
1
2
|
istream& read(
char
*buffer,
int
len);
ostream& write(
const
char
* buffer,
int
len);
|
字符指针buffer指向内存中一段存储空间。len是读写的字节数。调用的方式为:
1
2
|
a. write(p1,50);
b. read(p2,30);
|
上面第一行中的a是输出文件流对象,write函数将字符指针p1所给出的地址开始的50个字节的内容不加转换地写到磁盘文件中。在第二行中,b是输入文件流对象,read 函数从b所关联的磁盘文件中,读入30个字节(或遇EOF结束),存放在字符指针p2所指的一段空间内.
[例] 将一批数据以二进制形式存放在磁盘文件中.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#include <fstream>
using
namespace
std;
struct
student
{
char
name[20];
int
num;
int
age;
char
sex;
};
int
main( )
{
student stud[3]={
"Li"
,1001,18,
'f'
,
"Fun"
,1002,19,
'm'
,
"Wang"
,1004,17,
'f'
};
ofstream outfile(
"stud.dat"
,ios::binary);
if
(!outfile)
{
cerr<<
"open error!"
<<endl;
abort
( );
//退出程序
}
for
(
int
i=0;i<3;i++)
outfile.write((
char
*)&stud[i],
sizeof
(stud[i]));
outfile.close( );
return
0;
}
|
用成员函数write向stud.dat输出数据,从前面给出的write函数的原型可以看出: 第1个形参是指向char型常变量的指针变量buffer,之所以用const声明,是因为不允许通过指针改变其指向数据的值。形参要求相应的实参是字符指针或字符串的首地址。现在要将结构体数组的一个元素(包含4个成员)一次输出到磁盘文件stud.dat。&tud[i] 是结构体数组第i个元素的首地址,但这是指向结构体的指针,与形参类型不匹配。因此 要用(char *)把它强制转换为字符指针。第2个参数是指定一次输出的字节数。sizeof (stud[i])的值是结构体数组的一个元素的字节数。调用一次write函数,就将从&tud[i]开始的结构体数组的一个元素输出到磁盘文件中,执行3次循环输出结构体数组的3个元素.
其实可以一次输出结构体数组的个元素,将for循环的两行改为以下一行:
1
|
outfile.write((
char
*)&stud[0],
sizeof
(stud));
|
执行一次write函数即输出了结构体数组的全部数据.
abort函数的作用是退出程序,与exit作用相同.
可以看到,用这种方法一次可以输出一批数据,效率较高。在输出的数据之间不必加入空格,在一次输出之后也不必加回车换行符。在以后从该文件读入数据时不是靠空格作为数据的间隔,而是用字节数来控制.
[例] 将刚才以二进制形式存放在磁盘文件中的数据读入内存并在显示器上显示.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#include <fstream>
using
namespace
std;
struct
student
{
string name;
int
num;
int
age;
char
sex;
};
int
main( )
{
student stud[3];
int
i;
ifstream infile(
"stud.dat"
,ios::binary);
if
(!infile)
{
cerr<<
"open error!"
<<endl;
abort
( );
}
for
(i=0;i<3;i++)
infile.read((
char
*)&stud[i],
sizeof
(stud[i]));
infile.close( );
for
(i=0;i<3;i++)
{
cout<<
"NO."
<<i+1<<endl;
cout<<
"name:"
<<stud[i].name<<endl;
cout<<
"num:"
<<stud[i].num<<endl;;
cout<<
"age:"
<<stud[i].age<<endl;
cout<<
"sex:"
<<stud[i].sex<<endl<<endl;
}
return
0;
}
|
运行时在显示器上显示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
NO.1
name: Li
num: 1001
age: 18
sex: f
NO.2
name: Fun
num: 1001
age: 19
sex: m
NO.3
name: Wang
num: 1004
age: 17
sex: f
|
请思考,能否一次读入文件中的全部数据,如:
1
|
infile.read((
char
*)&stud[0],
sizeof
(stud));
|
答案是可以的,将指定数目的字节读入内存,依次存放在以地址&tud[0]开始的存储空间中。要注意读入的数据的格式要与存放它的空间的格式匹配。由于磁盘文件中的数据是从内存中结构体数组元素得来的,因此它仍然保留结构体元素的数据格式。现在再读入内存,存放在同样的结构体数组中,这必然是匹配的。如果把它放到一个整型数组中,就不匹配了,会出错。 与文件指针有关的流成员函数 。
在磁盘文件中有一个文件指针,用来指明当前应进行读写的位置。在输入时每读入 一个宇节,指针就向后移动一个字节。在输出时每向文件输出一个字节,指针就向后移动 一个字节,随着输出文件中字节不断增加,指针不断后移。对于二进制文件,允许对指针进行控制,使它按用户的意图移动到所需的位置,以便在该位置上进行读写。文件流提供 一些有关文件指针的成员函数。为了查阅方便,将它们归纳为下表: 几点说明: 1) 这些函数名的第一个字母或最后一个字母不是g就是p。带 g的是用于输入的函数(g是get的第一个字母,以g作为输入的标识,容易理解和记忆), 带p的是用于输出的函数(P是put的第一个字母,以P作为输出的标识)。例如有两个 tell 函数,tellg用于输入文件,tellp用于输出文件。同样,seekg用于输入文件,seekp用于输出文件。以上函数见名知意,一看就明白,不必死记.
如果是既可输入又可输出的文件,则任意用seekg或seekp.
2) 函数参数中的“文件中的位置”和“位移量”已被指定为long型整数,以字节为单位。“参照位置”可以是下面三者之一: ios::beg 文件开头(beg是begin的缩写),这是默认值。 ios::cur 指针当前的位置(cur是current的缩写)。 ios::end 文件末尾。 它们是在ios类中定义的枚举常量。举例如下: infile.seekg(100); //输入文件中的指针向前移到字节位置 infile.seekg(-50,ios::cur); //输入文件中的指针从当前位置后移字节 outfile.seekp(-75,ios::end); //输出文件中的指针从文件尾后移字节 随机访问二进制数据文件 。
一般情况下读写是顺序进行的,即逐个字节进行读写。但是对于二进制数据文件来说,可以利用上面的成员函数移动指针,随机地访问文件中任一位置上的数据,还可以修改文件中的内容.
[例] 有个学生的数据,要求: 把它们存到磁盘文件中; 将磁盘文件中的第,3,5个学生数据读入程序,并显示出来; 将第个学生的数据修改后存回磁盘文件中的原有位置。 从磁盘文件读入修改后的个学生的数据并显示出来.
要实现以上要求,需要解决个问题: 由于同一磁盘文件在程序中需要频繁地进行输入和输出,因此可将文件的工作方式指定为输入输出文件,即ios::in|ios::out|ios::binary。 正确计算好每次访问时指针的定位,即正确使用seekg或seekp函数。 正确进行文件中数据的重写(更新).
可写出以下程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
#include <fstream>
using
namespace
std;
struct
student
{
int
num;
char
name[20];
float
score;
};
int
main( )
{
student stud[5]={1001,
"Li"
,85,1002,
"Fun"
,97.5,1004,
"Wang"
,54,1006,
"Tan"
,76.5,1010,
"ling"
,96};
fstream iofile(
"stud.dat"
,ios::in|ios::out|ios::binary);
//用fstream类定义输入输出二进制文件流对象iofile
if
(!iofile)
{
cerr<<
"open error!"
<<endl;
abort
( );
}
for
(
int
i=0;i<5;i++)
//向磁盘文件输出个学生的数据
iofile.write((
char
*)&stud[i],
sizeof
(stud[i]));
student stud1[5];
//用来存放从磁盘文件读入的数据
for
(
int
i=0;i<5;i=i+2)
{
iofile.seekg(i*
sizeof
(stud[i]),ios::beg);
//定位于第,2,4学生数据开头
//先后读入个学生的数据,存放在stud1[0],stud[1]和stud[2]中
iofile.read((
char
*)&stud1[i/2],
sizeof
(stud1[0]));
//输出stud1[0],stud[1]和stud[2]各成员的值
cout<<stud1[i/2].num<<
" "
<<stud1[i/2].name<<
" "
<<stud1[i/2].score<<endl;
}
cout<<endl;
stud[2].num=1012;
//修改第个学生(序号为)的数据
strcpy
(stud[2].name,
"Wu"
);
stud[2].score=60;
iofile.seekp(2*
sizeof
(stud[0]),ios::beg);
//定位于第个学生数据的开头
iofile.write((
char
*)&stud[2],
sizeof
(stud[2]));
//更新第个学生数据
iofile.seekg(0,ios::beg);
//重新定位于文件开头
for
(
int
i=0;i<5;i++)
{
iofile.read((
char
*)&stud[i],
sizeof
(stud[i]));
//读入个学生的数据
cout<<stud[i].num<<
" "
<<stud[i].name<<
" "
<<stud[i].score<<endl;
}
iofile.close( );
return
0;
}
|
运行情况如下:
1
2
3
4
5
6
7
8
9
|
1001 Li 85(第个学生数据)
1004 Wang 54 (第个学生数据)
1010 ling 96 (第个学生数据)
1001 Li 85 (输出修改后个学生数据)
1002 Fun 97.5
1012 Wu 60 (已修改的第个学生数据)
1006 Tan 76.5
1010 ling 96
|
。
本程序也可以将磁盘文件stud.dat先后定义为输出文件和输入文件,在结束第一次的输出之后关闭该文件,然后再按输入方式打开它,输入完后再关闭它,然后再按输出方式打开,再关闭,再按输入方式打开它,输入完后再关闭。显然这是很烦琐和不方便的。 在程序中把它指定为输入输出型的二进制文件。这样,不仅可以向文件添加新的数据或读入数据,还可以修改(更新)数据。利用这些功能,可以实现比较复杂的输入输出任务.
请注意,不能用ifstream或ofstream类定义输入输出的二进制文件流对象,而应当用fstream类.
最后此篇关于详解C++编程中对二进制文件的读写操作的文章就讲到这里了,如果你想了解更多关于详解C++编程中对二进制文件的读写操作的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试打印 timeval 类型的值。实际上我可以打印它,但我收到以下警告: 该行有多个标记 格式“%ld”需要“long int”类型,但参数 2 的类型为“struct timeval” 程序
我正在编写自己的 unix 终端,但在执行命令时遇到问题: 首先,我获取用户输入并将其存储到缓冲区中,然后我将单词分开并将它们存储到我的 argv[] 数组中。IE命令是“firefox”以启动存储在
我是 CUDA 的新手。我有一个关于一个简单程序的问题,希望有人能注意到我的错误。 __global__ void ADD(float* A, float* B, float* C) { con
我有一个关于 C 语言 CGI 编程的一般性问题。 我使用嵌入式 Web 服务器来处理 Web 界面。为此,我在服务器中存储了一个 HTML 文件。在此 HTML 文件中包含 JavaScript 和
**摘要:**在代码的世界中,是存在很多艺术般的写法,这可能也是部分程序员追求编程这项事业的内在动力。 本文分享自华为云社区《【云驻共创】用4种代码中的艺术试图唤回你对编程的兴趣》,作者: break
我有一个函数,它的任务是在父对象中创建一个变量。我想要的是让函数在调用它的级别创建变量。 createVariable testFunc() [1] "test" > testFunc2() [1]
以下代码用于将多个连续的空格替换为1个空格。虽然我设法做到了,但我对花括号的使用感到困惑。 这个实际上运行良好: #include #include int main() { int ch, la
我正在尝试将文件写入磁盘,然后自动重新编译。不幸的是,某事似乎不起作用,我收到一条我还不明白的错误消息(我是 C 初学者 :-)。如果我手动编译生成的 hello.c,一切正常吗?! #include
如何将指针值传递给结构数组; 例如,在 txt 上我有这个: John Doe;xxxx@hotmail.com;214425532; 我的代码: typedef struct Person{
我尝试编写一些代码来检索 objectID,结果是 2B-06-01-04-01-82-31-01-03-01-01 . 这个值不正确吗? // Send a SysObjectId SNMP req
您好,提前感谢您的帮助, (请注意评论部分以获得更多见解:即,以下示例中的成本列已添加到此问题中;西蒙提供了一个很好的答案,但成本列本身并未出现在他的数据响应中,尽管他提供的功能与成本列一起使用) 我
我想知道是否有人能够提出一些解决非线性优化问题的软件包的方法,而非线性优化问题可以为优化解决方案提供整数变量?问题是使具有相等约束的函数最小化,该函数受某些上下边界约束的约束。 我已经在R中使用了'n
我是 R 编程的初学者,正在尝试向具有 50 列的矩阵添加一个额外的列。这个新列将是该行中前 10 个值的平均值。 randomMatrix <- generateMatrix(1,5000,100,
我在《K&R II C 编程 ANSI C》一书中读到,“>>”和“0; nwords--) sum += *buf++; sum = (sum >>
当下拉列表的选择发生变化时,我想: 1) 通过 div 在整个网站上显示一些 GUI 阻止覆盖 2)然后处理一些代码 3) 然后隐藏叠加层。 问题是,当我在事件监听器函数中编写此逻辑时,将执行 onC
我正在使用 Clojure 和 RESTEasy 设计 JAX-RS REST 服务器. 据我了解,用 Lisp 系列语言编写的应用程序比用“传统”命令式语言编写的应用程序更多地构建为“特定于领域的语
我目前正在研究一种替代出勤监控系统作为一项举措。目前,我设计的用户表单如下所示: Time Stamp Userform 它的工作原理如下: 员工将选择他/她将使用的时间戳类型:开始时间、超时、第一次
我是一名学生,试图自学编程,从在线资源和像您这样的人那里获得帮助。我在网上找到了一个练习来创建一个小程序来执行此操作: 编写一个程序,读取数字 a 和 b(长整型)并列出 a 和 b 之间有多少个数字
我正在尝试编写一个 shell 程序,给定一个参数,打印程序的名称和参数中的每个奇数词(即,不是偶数词)。但是,我没有得到预期的结果。在跟踪我的程序时,我注意到,尽管奇数词(例如,第 5 个词,5 %
只是想知道是否有任何 Java API 可以让您控制台式机/笔记本电脑外壳上的 LED? 或者,如果不可能,是否有可能? 最佳答案 如果你说的是前面的 LED 指示电源状态和 HDD 繁忙状态,恐怕没
我是一名优秀的程序员,十分优秀!