当前位置首页 > 百科> 正文

C++档案流

2019-09-04 09:30:00 百科
C++档案流

C++档案流

流,简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具。在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程式设计师是对流进行所有操作的,而不用关心流的另一头数据的真正流向。流不但可以处理档案,还可以处理动态记忆体、网路数据等多种数据形式。如果你对流的操作非常熟练,在程式中利用流的方便性,写起程式会大大提高效率的。

基本介绍

  • 程式语言:C++
  • :std标準库
  • 包含档案:fstream(新) 或 fstream.h(旧)
  • 命名空间:std
  • C++类:fstream
  • C++派生类:ifstream ofstream

简介

在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的档案I/O,stream这个类有两个重要的运算符:
1、插入器(<<)
向流输出数据。比如说系统有一个默认的标準输出流(cout),一般情况下就是指的显示器,所以,
cout<<"WriteStdout"<<'\n';
就表示把字元串"Write Stdout"和换行字元('\n')输出到标準输出流。
2、析取器(>>)
从流中输入数据。比如说系统有一个默认的标準输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标準输入流中读取一个指定类型(即变数x的类型)的数据。
在C++中,对档案的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作档案,就必须加入头档案fstream.h。下面就把此类的档案操作过程一一道来。

C++ 中 *fstream 操作

建立档案

为了通过流对档案进行操作,应先建立档案流对象,如下所示:
ifstream iFile;ofstream oFile;fstream ioFile;
这里定义了iFile,oFile,ioFile三个档案流对象。iFile是输入档案流对象;oFile是输出档案流对象;ioFile是输入输出档案流对象。

打开档案

在fstream类中,有一个成员函式open(),就是用来打开档案的,其原型是:
voidopen(constchar*filename,intmode,intaccess);
参数:
filename:要打开的档案名称mode:要打开档案的方式access:打开档案的属性
打开档案的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:
ios::app:以追加的方式打开档案ios::ate:档案打开后定位到档案尾,ios:app就包含有此属性ios::binary:以二进制方式打开档案,预设的方式是文本方式。两种方式的区别见前文ios::in:档案以输入方式打开ios::out:档案以输出方式打开ios::nocreate:不建立档案,所以档案不存在时打开失败ios::noreplace:不覆盖档案,所以保存档案时如果档案存在失败ios::trunc:如果档案存在,把档案长度设为0
可以用“或”把以上属性连线起来,如ios::out|ios::binary
// 注:新的C++标準库不支持nocreate和noreplace,以前的旧版本可以用.
打开档案的属性取值是:
0:普通档案,打开访问1:唯读档案2:隐含档案4:系统档案
可以用“或”或者“+”把以上属性连线起来 ,如3或1|2就是以唯读和隐含属性打开档案。
例如:以二进制输入方式打开档案c:config.sys
fstreamfile1;file1.open("c:config.sys",ios::binary|ios::in,0);
如果open函式只有档案名称一个参数,则是以读/写普通档案打开,即:
file1.open("c:config.sys");<=>file1.open("c:config.sys",ios::in|ios::out,0);
另外,fstream还有和open()一样的构造函式,对于上例,在定义的时候就可以打开档案了:
fstreamfile1("c:config.sys");
特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(output file stream),ifstream默认以输入方式打开档案,而ofstream默认以输出方式打开档案。
ifstreamfile2("c:pdos.def");//以输入方式打开档案ofstreamfile3("c:x.123");//以输出方式打开档案
所以,在实际套用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。
包含:
需要在档案中包含<fstream>,即:
#include<fstream>
后面可以加using namespace std;程式里就可以直接用fstream类及其函式了。
或者在具体使用时用std::来标识,如:std::fstream file1;
例如:fstream file;
file.open("filename.txt",ios::out);

关闭档案

打开的档案使用完成后一定要关闭,fstream提供了成员函式close()来完成此操作,如:file1.close();就把file1相连的档案关闭。

读写档案

读写档案分为文本档案和二进制档案的读取,对于文本档案的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要複杂些,下面就详细的介绍这两种方式
1、文本档案的读写
文本档案的读写很简单:用插入器(<<)向档案输出;用析取器(>>)从档案输入。假设file1是以输入方式打开,file2以输出打开。示例如下:
file2<<"I Love You";//向档案写入字元串"I Love You"
int i;
file1>>i;//从档案输入一个整数值。
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
操纵符 功能 输入/输出
dec格式化为十进制数值数据输入和输出endl输出一个换行符并刷新此流输出ends输出一个空字元输出hex格式化为十六进制数值数据输入和输出oct格式化为八进制数值数据输入和输出//setpxecision(intp)设定浮点数的精度位数输出setprecision(intp)设定浮点数的精度位数输出
(setpxecision应该为setprecision,使用时需要包含头档案:#include <iomanip.h>)
//比如要把123当作十六进制输出:file1<<hex<<123;要把3.1415926以5位精度输出:file1<<setprecision(5)<<3.1415926。
2、二进制档案的读写
①put()
put()函式向流写入一个字元,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字元'c'。
②get()
get()函式比较灵活,有3种常用的重载形式:
一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字元,结果保存在引用ch中,如果到档案尾,返回空字元。如file2.get(x);表示从档案中读取一个字元,并把读取的字元保存在x中。
另一种重载形式的原型是: int get();这种形式是从流中返回一个字元,如果到达档案尾,返回EOF,如x=file2.get();和上例功能是一样的。
还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='n');这种形式把字元读入由 buf 指向的数组,直到读入了 num 个字元或遇到了由 delim 指定的字元,如果没使用 delim 这个参数,将使用预设值换行符'n'。例如:
file2.get(str1,127,'A');//从档案中读取字元到字元串str1,当遇到字元'A'或读取了127个字元时终止。
③读写数据块
要读写二进制数据块,使用成员函式read()和write()成员函式,它们原型如下:
read(unsigned char *buf,int num);
write(const unsigned char *buf,int num);
read()从档案中读取 num 个字元到 buf 指向的快取中,如果在还未读入 num 个字元时就到了档案尾,可以用成员函式 int gcount();来取得实际读取的字元数;而 write() 从buf 指向的快取写 num 个字元到档案中,值得注意的是快取的类型是 unsigned char *,有时可能需要类型转换。
例:
unsigned char str1[]="ILoveYou";int n[5];ifstream in("xxx.xxx");ofstream out("yyy.yyy");out.write(str1,strlen(str1));            //把字元串str1全部写到yyy.yyy中in.read((unsignedchar*)n,sizeof(n));    //从xxx.xxx中读取指定个整数,注意类型转换in.close();out.close();

错误标誌

iostatevalue
(member
constant)
indicatesfunctions to
check state
flags




goodbit
No errors (zero valueiostate)
true
false
false
false
goodbit
eofbit
End-of-File reached on input operation
false
true
false
false
eofbit
failbit
Logical error on i/o operation
false
false
true
false
failbit
badbit
Read/writing error on i/o
operation
false
false
true
true
badbit

检测EOF

成员函式eof()用来检测是否到达档案尾,如果到达档案尾返回非0值,否则返回0。原型是int eof();
例: if(in.eof())ShowMessage("已经到达档案尾!");
出现eof标誌如果用clear(),eof标誌会被清除,这时需要手动检查或在下一次操作时重新置位
手动检查
autolastpos=in,tellg();in.seekg(0,ios::end);autoendpos=in.tellg();in.seekg(lastpos);

档案定位

和C的档案操作方式不同的是,C++ I/O系统管理两个与一个档案相联繫的指针。一个是读指针,它说明输入操作在档案中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的档案定位分为读位置和写位置的定位,对应的成员函式是 seekg()和 seekp(),seekg()是设定读位置,seekp是设定写位置。
使用seekg和seekp时移动的是同一个指针,可以通过下面程式检测
fstreamfile;//需要保证档案一定打开成功    file.open("1.txt",ios::binary|ios::trunc|ios::in|ios::out);    file.write("ABCDEFGHIJ",10);    //写指针应该是10    printf("%u\n",(size_t)file.tellp());    //设定读指针为0    file.seekg(0,ios::beg);    //可以发现写指针变成0了    printf("%u\n",(size_t)file.tellp());
seekg()和seekp()返回的流尚未研究,尚不清楚与本体的关係,需后来人补充
tellp或tellg()返回的值不能直接使用,必须转换为C++基本值
size_tpos1=file.tellg().seekpos();//或size_tpos2=(size_t)file.tellg();
它们最通用的形式如下:
istream&seekg(streamoffoffset,seek_dirorigin);ostream&seekp(streamoffoffset,seek_dirorigin);
streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基準位置,是一个有以下值的枚举:
ios::beg:档案开头ios::cur:档案当前位置ios::end:档案结尾
这两个函式一般用于二进制档案,因为文本档案会因为系统对字元的解释而可能与预想的值不同。
例:
file1.seekg(1234,ios::cur);//把档案的读指针从当前位置向后移1234个位元组file2.seekp(1234,ios::beg);//把档案的写指针从档案开头向后移1234个位元组
如果vc编程的话最好使用CFile类等更加方便于档案操作</CA>

流对象的传递

stream的声明里面是将拷贝构造函式声明为非public的,应此在将stream作为函式参数传递时应该使用引用或者指针,而非值传递。
例如:
voidfn(streamin);
这样的声明在编译时无问题,但是在使用时即会提示错误,应该修改为
voidfn(stream&in);
声明:此文信息来源于网络,登载此文只为提供信息参考,并不用于任何商业目的。如有侵权,请及时联系我们:baisebaisebaise@yeah.net