C++初学者指南 第十一篇(9)

来源:互联网 发布:java 多线程 超时 编辑:程序博客网 时间:2024/06/07 07:14
转载请标明出处:http://blog.csdn.net/zhangxingping

基本技能11.9:非格式化的二进制文件的输入/输出

尽管文本文件的读写是比较简单的,但这并不是处理文件的最有效的方式。另外,有时候我们是需要存储非格式化的二进制数据的,而不是文本数据。我们将在下面描述实现这些功能的函数。

当我们对一个文件进行二进制操作的时候,必须确保它是使用ips::binary模式被打开的。尽管这些非格式化的文件操作函数对于文本模式的文件也是起作用的,但是其中会进行字符转换的。字符转换与我们进行二进制文件操作的目的是相背的。

    通常情况下,两种方式来从二进制文件中读取或者是向二进制文件中写入数据的。第一种方法就是使用put()函数向文件中写入一字节,使用get()从文件中读入一个字节;第二种方法就是使用块函数进行输入输出:read()write()。下面逐一进行讨论、

 

使用get()put()

    get()函数由很多种形式,但是最常用的是如下的形式,put()函数也是一样:

istream & get(char *ch);

ostream &put(char ch);

其中,get()函数从相关联的流中读取一个字符,并把值赋给变量ch。这个函数返回相关流的引用。如果没有到达文件的结尾,该函数返回非空值。put()函数是ch的值写入到相关的流中并返回对这个流的引用。

下面的程序将会把任意文件的内容显示在屏幕上。其中使用到了get()函数:

//使用get()来显示一个文件的内容#include <iostream>#include <fstream> using namespace std; int main(int argc, char * argv[]){    char ch;        if (argc != 2)    {        cout <<"Usage: PR<filename> \n";        return 1;    }     ifstream in(argv[1], ios::in | ios::binary);    if (!in)    {        cout << "Cannot open file.\n";        return 1;    }     while( in)//in的值将会是false,如果遇到了文件末尾    {        in.get(ch); //in         if(in)        {            cout << ch;        }}    in.close();     return 0;}


请注意其中的while循环。当读取到文件末尾的时候in在布尔表达式中的值将会是false,这样while循环就结束了。

其实还有一种更简便的从文件中读取字符并显示该字符的循环方式,如下:

while(in.get(ch)){    cout<<ch;}

之所以这样写也是可以的,是因为get()函数返回的是in的流,当遇到文件结尾的时候in将会被认为是false。下面的程序使用put()函数来吧一个字符串写入到文件中。

//使用put()函数来向文件写入数据#include <iostream>#include <fstream>using namespace std; int main(){    char * p ="hello there.\n";     ofstream out("test", ios::out | ios::binary);    if (!out)    {        cout << "Cannot open file.\n";        return 1;    }     //写入字符到文件中,知道遇到字符串结束标记    while(*p)    {        out.put(*p++); //使用put把字符串写入到文件中,将不会进行字符转换。    }    out.close();     return 0;}

执行该程序后,文件test的内容将是字符串”hello there.”后接着一个换行字符。这种方式不会进行字符转换。

 

读取和写入块数据

    我们使用read()write()来读取和写入块数据。它们的原型如下:

istream &read(char *buf, streamsize num);

ostream &write(const char *buf, streamsize num);

其中的read()函数从相关联的流中读取num指示的字节大小的数据,并把这些数据存储在buf指示的空间中。write()函数则是把从buf开始的大小为num的空间中的数据写入到相关联的流中。正如我们在前面提到的那样,streamsize是由C++定义的原型为整型数的类型。它的表示范围足以表示任何一种输入输出操作可以传输的字节的数量。

下面的程序先把一组整型数写入文件,然后再从文件中出入:

//使用read()和write()函数 #include <iostream>#include <fstream>using namespace std; int main(){    int n[5] = {1,2,3,4,5};    register int i;    ofstream out("test",ios::out|ios::binary);    if(!out)    {        cout <<"Cannot open file.\n" ;        return 1;    }    out.write((char*)&n,sizeof(n)); //写块数据到文件中    out.close();     for( i = 0;i < 5; i++) //清除数组中的数据    {        n[i] = 0;    }     ifstream in("test",ios::in|ios::binary);    if(!in)    {        cout << "Cannot pen file.\n";        return 1;    }    in.read((char*)&n, sizeof(n));//从文件中读取块数据     for( i = 0; i< 5; i++)    {        cout << n[i] << " ";    }     in.close();     return 0; }

    请注意,在上面的程序中我们在调用函数read()write()的时候都进行了强制的类型转换。如果一个缓冲区不是以字符数组的形式定义的,那么这样做时完全有必要的。

    如果在读取num指定字节的时候遇到了文件结尾,则函数会停止从流中读取数据,并把当前读取到的可用的字节数的数据放入到缓冲区中。我们可以通过调用gcount()来查询实际上读取到得字符的数量。它的原型如下:

streamsize gcount();

该函数返回的是最后一次进行输入操作的字符的数量。

 

练习

1. 如果想进行二进制的读写,则文件应该以什么模式进行打开?

2. get()put()函数是用来做什么用的?

3. 哪个函数可以被用来读取块数据?