写在前面的话:C++中对文件的操作跟C语言是有很大差别的,因此总结一下C++对文件的操作。
1、通常用法
在C++中队文件的输入输出流和对内存的输入输出流以及对字符串的输入输出流接口是一致的,如果输入流能产生字节,可以用一个提取操作符从这个流中获取信息。这个提取符产生并格式化目的对象所期望的信息类型。虽然输入流用起来很方便,但是也有一个问题,在使用格式化的输入机制,尤其是标准输入时,会遇到和C语言中scanf()中同样的问题。如果输入一个非期望值,进程则被偏离,而且它很难恢复。另外,格式化的输入缺省以空格为分隔符。那么如下面的代码:
#include <iostream> using namespace std; int main(void) { int i; cin >> i; float f; cin >> f; char c; cin >> c; char buf[100]; cin >> buf; cout << "i = " << i << endl; cout << "f = " << f << endl; cout << "c = " << c << endl; cout << "buf = " << buf << endl; cout << flush; cout << hex << "0x" << i << endl; return 0; }
给出以下输入:
12 1.4 c this is a test
我们应该得到与输入相同的输出。
12
1.4
c
this is a test
但是实际输出为:
12
1.4
c
this
注意到buf只得到第一个字,这个由于输入机制是通过寻找空格来分隔输入的,而空格在“this”的后面。另外如果连续的输入串长于为buf分配的存储空间,也会发生buf溢出现象。
2、面向行的输入
要获取一行输入,有两种选择:成员函数get()、getline()。两个函数都是有三个参数:指向存储结果缓冲区的指针、缓冲区大小(不能超过其限度)和知道什么时候停止输入的终止符。终止符有一个经常用到的缺省值‘ ’。两个函数遇到输入终止符时,都把零存储在结果缓冲区里。
它们的区别如下:
1. get()遇到输入流的分隔符就停止,而不从输入流中提取分隔符。如果用相同的分隔符再调用一次get()函数,它会立即返回而不带任何输入。
2. getline()与其相反,它从输入流中提取分隔符,但仍没有把存储在结果缓冲区里。
总之,当我们在处理文本文件时,无论什么时候需要读出一行,都会想到getline()函数。
3、读取原始字节
如果要读取原始字节,即二进制代码的话,可以使用read()函数,第一个参数指向内存目的地址的指针,第二个参数指明要读取的字节数。
4、写入原始字节
如果要写入原始字节,使用write()函数。
遇到的问题:输入流什么时候返回假值?
如下面的程序:
#include <iostream> #include <fstream> #include <assert.h> using namespace std; const int SZ = 100; int main() { char buf[SZ]; { ifstream in("strfile.cpp"); assert(in); ofstream out("strfile.out"); assert(out); int i = 1; while(in.get(buf, SZ)) { in.get(); // throw away next character cout << buf << endl; out << i++ << ": " << buf << endl; } } ifstream in("strfile.out"); assert(in); while(in.getline(buf, SZ)) { char *cp = buf; while(*cp != ':') { cp++; } cp += 2; cout << cp << endl; // must still add } }
其中的文件输入流不是应该在文件结尾处才返回假值么?但是实际运行是,如果遇到空行程序就从while循环中跳出了,这个为什么呢?