printf("name[%d]=%-20s:
size[%d]=%d\n",i,s[i].name,i,s[i].size);
}
执行
name[0]=Linux!
size[0]=6
name[1]=FreeBSD!
size[1]=8
name[2]=Windows2000size[2]=11
fwrite(将数据写至文件流)
相关函数
fopen,fread,fseek,fscanf
表头文件
#include<>
定义函数
size_tfwrite(constvoid*ptr,size_tsize,size_tnmemb,FILE*stream);
函数说明
fwrite()用来将数据写入文件流中。
参数stream为已打开的文件指针,参数ptr指向欲写入的数据地址,总共写入的字符数以参数size*nmemb来决定。
Fwrite()会返回实际写入的nmemb数目。
返回值
返回实际写入的nmemb数目。
范例
#include<>
#defineset_s(x,y){strcoy(s[x].name,y);s[x].size=strlen(y);}
#definenmemb3
structtest
{
charname[20];
intsize;
}s[nmemb];
main()
{
FILE*stream;
set_s(0,"Linux!
");
set_s(1,"FreeBSD!
");
set_s(2,"Windows2000.");
stream=fopen("/tmp/fwrite","w");
fwrite(s,sizeof(structtest),nmemb,stream);
fclose(stream);
}
执行
参考fread()
fseek()函数
调用形式:
#include""
fseek(文件类型指针fp,位移量,起始点);
函数功能:
把与fp有关的文件位置指针放到一个指定位置。
其中,“位移量”是long型数据,它表示位置指针相对于“起始点”移动的字节数。
如果位移量是一个正数,表示从“起始点”开始往文件尾方向移动;如果位移量是一个负数,则表示从“起始点”开始往文件头方向移动。
“起始点”不能任意设定,它只能是在中定义的三个符号常量之一:
起始点
对应的数字
代表的文件位置
SEEK_SET
0
文件开头
SEEK_CUR
1
文件当前位置
SEEK_END
2
文件末尾
例如:
fseek(fp,50L,0);或fseek(fp,50L,SEEK_SET);
其作用是将位置指针移到离文件头50个字节处。
C++通过以下几个类支持文件的输入输出:
ofstream:
写操作(输出)的文件类(由ostream引申而来)
ifstream:
读操作(输入)的文件类(由istream引申而来)
fstream:
可同时读写操作的文件类(由iostream引申而来)
打开文件(Openafile)
对这些类的一个对象所做的第一个操作通常就是将它和一个真正的文件联系起来,也就是说打开一个文件。
被打开的文件在程序中由一个流对象(streamobject)来表示(这些类的一个实例),而对这个流对象所做的任何输入输出操作实际就是对该文件所做的操作。
要通过一个流对象打开一个文件,我们使用它的成员函数open():
voidopen(constchar*filename,openmodemode);这里filename是一个字符串,代表要打开的文件名,mode是以下标志符的一个组合:
ios:
:
in为输入(读)而打开文件
ios:
:
out为输出(写)而打开文件
ios:
:
ate初始位置:
文件尾
ios:
:
app所有输出附加在文件末尾
ios:
:
trunc如果文件已存在则先删除该文件
ios:
:
binary二进制方式
这些标识符可以被组合使用,中间以”或”操作符(|)间隔。
例如,如果我们想要以二进制方式打开文件””来写入一些数据,我们可以通过以下方式调用成员函数open()来实现:
ofstreamfile;
("",ios:
:
out|ios:
:
app|ios:
:
binary);ofstream,ifstream和fstream所有这些类的成员函数open都包含了一个默认打开文件的方式,这三个类的默认方式各不相同:
类参数的默认方式
ofstreamios:
:
out|ios:
:
trunc
ifstreamios:
:
in
fstreamios:
:
in|ios:
:
out
只有当函数被调用时没有声明方式反a3b数的情况下,默认值才会被采用。
如果函数被调用时声明了任何参数,默认值将被完全改写,而不会与调用参数组合。
由于对类ofstream,ifstream和fstream的对象所进行的第一个操作通常都是打开文件,这些类都有一个构造函数可以直接调用open函数,并拥有同样的参数。
这样,我们就可以通过以下方式进行与上面同样的定义对象和打开文件的操作:
ofstreamfile("",ios:
:
out|ios:
:
app|ios:
:
binary);两种打开文件的方式都是正确的。
你可以通过调用成员函数is_open()来检查一个文件是否已经被顺利的打开了:
boolis_open();它返回一个布尔(bool)值,为真(true)代表文件已经被顺利打开,假(false)则相反。
关闭文件(Closingafile)
当文件读写操作完成之后,我们必须将文件关闭以使文件重新变为可访问的。
关闭文件需要调用成员函数close(),它负责将缓存中的数据排放出来并关闭文件。
它的格式很简单:
voidclose();这个函数一旦被调用,原先的流对象(streamobject)就可以被用来打开其它的文件了,这个文件也就可以重新被其它的进程(process)所有访问了。
为防止流对象被销毁时还联系着打开的文件,析构函数(destructor)将会自动调用关闭函数close。
文本文件(Textmodefiles)
类ofstream,ifstream和fstream是分别从ostream,istream和iostream中引申而来的。
这就是为什么fstream的对象可以使用其父类的成员来访问数据。
一般来说,我们将使用这些类与同控制台(console)交互同样的成员函数(cin和cout)来进行输入输出。
如下面的例题所示,我们使用重载的插入操作符<<:
n”;
examplefile<<“Thisisanotherline.\n”;
();
}
return0;
}file
Thisisaline.
Thisisanotherline.
从文件中读入数据也可以用与cin的使用同样的方法:
Thisisanotherline.
上面的例子读入一个文本文件的内容,然后将它打印到屏幕上。
注意我们使用了一个新的成员函数叫做eof,它是ifstream从类ios中继承过来的,当到达文件末尾时返回true。
状态标志符的验证(Verificationofstateflags)
除了eof()以外,还有一些验证流的状态的成员函数(所有都返回bool型返回值):
bad()如果在读写过程中出错,返回true。
例如:
当我们要对一个不是打开为写状态的文件进行写入时,或者我们要写入的设备没有剩余空间的时候。
fail()除了与bad()同样的情况下会返回true以外,加上格式错误时也返回true,例如当想要读入一个整数,而获得了一个字母的时候。
eof()如果读文件到达文件末尾,返回true。
good()这是最通用的:
如果调用以上任何一个函数返回true的话,此函数返回false。
要想重置以上成员函数所检查的状态标志,你可以使用成员函数clear(),没有参数。
获得和设置流指针(getandputstreampointers)
所有输入/输出流对象(i/ostreamsobjects)都有至少一个流指针:
ifstream,类似istream,有一个被称为getpointer的指针,指向下一个将被读取的元素。
ofstream,类似ostream,有一个指针putpointer,指向写入下一个元素的位置。
fstream,类似iostream,同时继承了get和put
我们可以通过使用以下成员函数来读出或配置这些指向流中读写位置的流指针:
tellg()和tellp()这两个成员函数不用传入参数,返回pos_type类型的值(根据ANSI-C++标准),就是一个整数,代表当前get流指针的位置(用tellg)或put流指针的位置(用tellp).
seekg()和seekp()这对函数分别用来改变流指针get和put的位置。
两个函数都被重载为两种不同的原型:
seekg(pos_typeposition);
seekp(pos_typeposition);
使用这个原型,流指针被改变为指向从文件开始计算的一个绝对位置。
要求传入的参数类型与函数tellg和tellp的返回值类型相同。
seekg(off_typeoffset,seekdirdirection);
seekp(off_typeoffset,seekdirdirection);
使用这个原型可以指定由参数direction决定的一个具体的指针开始计算的一个位移(offset)。
它可以是:
ios:
:
beg从流开始位置计算的位移
ios:
:
cur从流指针当前位置开始计算的位移
ios:
:
end从流末尾处开始计算的位移
流指针get和put的值对文本文件(textfile)和二进制文件(binaryfile)的计算方法都是不同的,因为文本模式的文件中某些特殊字符可能被修改。
由于这个原因,建议对以文本文件模式打开的文件总是使用seekg和seekp的第一种原型,而且不要对tellg或tellp的返回值进行修改。
对二进制文件,你可以任意使用这些函数,应该不会有任何意外的行为产生。
以下例子使用这些函数来获得一个二进制文件的大小:
n”;
return0;
}sizeof
is40bytes.
二进制文件(Binaryfiles)
在二进制文件中,使用<<和>>,以及函数(如getline)来操作符输入和输出数据,没有什么实际意义,虽然它们是符合语法的。
文件流包括两个为顺序读写数据特殊设计的成员函数:
write和read。
第一个函数(write)是ostream的一个成员函数,都是被ofstream所继承。
而read是istream的一个成员函数,被ifstream所继承。
类fstream的对象同时拥有这两个函数。
它们的原型是:
write(char*buffer,streamsizesize);
read(char*buffer,streamsizesize);
这里buffer是一块内存的地址,用来存储或读出数据。
参数size是一个整数值,表示要从缓存(buffer)中读出或写入的字符数。
问题1:
直接将这个整数98341写入到文本文件中,然后打开文件得到是是否是这个整数呢
问题2:
文本和二进制的存储方式,是以什么方式存储,它们之间的差别是什么,在实际应用中需要注意什么呢
计算结果1:
(直接将这个整数98341写入到文本文件中再打开后的结果)
CODE:
FILE*pFile=fopen("","w");
nti=98341;
fwrite(&i,4,1,pFile);
close(pFile);
运行结果:
从结果可以看出,显示的是乱码,并没有得到我们想要的结果,为什么呢
然后用二进制方式打开这个文本文件后的结果如下:
结果是:
00018025,转换为十进制就是98341,说明其结果是正确的,但为会直接打开显示的确不正确
计算结果2:
(以98341这5个字符的ASCII码方式存储)
CODE:
FILE*pFile=fopen("","w");
charch[5];
ch[0]=9+48;
ch[1]=8+48;
ch[2]=3+48;
ch[3]=4+48;
ch[4]=1+48;
fwrite(ch,1,5,pFile);
fclose(pFile);
结果:
大家可以看到,这次显示结果正确
(3)利用itoa函数将整数转换为字符串进行存储
CODE:
FILE*pFile=fopen("","w");
inti=98341;
charch[5];
itoa(i,ch,10);
fwrite(ch,1,5,pFile);
fclose(pFile);
结果:
结果也显示正确!
那么为什么直接把一个整数放进去读取出来的结果就不对
分析:
对于文本文件来说,它的第一个字节存放的是可表示为一个字符的ASCII代码,如果想记事本中看到“98341”这几个字符,实际上看到的是这些字符相应的ASCII码转换后的字符,换句话说,看到的“98341”是5个字符,而不在是一个整数.
问题原因:
以文本方式打开文件时,该文件中存储的每一个字节的数据都要作为ASCII码转换为相应的字符,但是它的每一个字节的数据转换为字符之后又是不可读的,所以看到的就是乱码。
结论:
所以,要是碰到这种对数字、数字和字符的存储,并要求以记事本打开时看到的是数字,具体办法就是先把这些整数数字转换为ASCII字符,然后再写入到文件中,这样直接读出文件中的字符就可以得到正确的结果了。
下文件的打开和保存
要用到的类是CFile
其声明格式是:
CFile(LPCTSTRlpszFileName,UINTnOpenFlags);
其中:
lpszFileName--指定文件名称
nOpenFlags---指定文件共享和访问方式
(1)文件的写入
CODE:
CFilefile("",CFile:
:
modeCreate|CFile:
:
modeWrite);
("VC学习",strlen("VC学习:
));
();
(2)文件的读取
CODE:
CFilefile("",CFile:
:
modeRead);
char*pBuf;
DWORDdwFileLen;
dwFileLen=();
pBuf=newchar[dwFileLen+1];
pBuf[dwFileLen]=0;
(pBuf,dwFileLen);
();
MessageBox(pBuf);