分类: C/C++
2008-05-28 16:09:49
一个有关fstream类的bug
近日写程序需要读出文件,对读出的内容作些修改,再写回到文件中。
突然发现一个莫名其妙的问题,写回去的时候居然在文件末尾增加了几个字
符。感到很不可思议。具体代码如下:
fstream infile;
infile.open("c:\\test.txt", ios::in);
infile.seekp(0, ios::end);
int iFileLen = infile.tellp();
cout << "File len:" << iFileLen << endl;
char * pBuff = new char[iFileLen + 1];
memset(pBuff, 0, iFileLen + 1);
infile.seekp(0, ios::beg);
infile.read(pBuff, iFileLen);
infile.close();
fstream outfile;
outfile.open("c:\\test1.txt", ios::out|ios::trunc);
outfile.write(pBuff, iFileLen);
outfile.close();
delete[] pBuff;
在文件test.txt中输入一个字符'.'以及一个回车键,用UE打开,发现该
文件有三个字符,十六进制表示如下:2E 0D 0A。而在屏幕中打印出来的文件
大小也是3。可是文件test1.txt文件大小却变成了4,其十六进制表示变成了:
2E 0D 0A 00。莫名其妙的多了一个字节。可是明明写入的字节数应该是3啊。
怎么写到文件中去却变成了4了呢?很奇怪的问题。难道是write的问题?于是
我换了一种写文件方式,改成下面的方式:
for(int i = 0; i < iFileLen; i++)
outfile << pBuff[i];
但是结果仍然同上,仍然多了一个字节。于是感到可能是fstream这个类的问
题,以前也发觉该类在使用seekp时会出错。于是改成用c语言的文件流读写
操作,具体实现如下:
FILE * f = fopen("c:\\test.txt", "r");
fseek(f, 0, SEEK_END);
int len = ftell(f);
printf("the file len: %d \n", len);
fseek(f, 0, SEEK_SET);
char * p = new char[len + 1];
memset(p, 0x00, len + 1);
fread(p, sizeof(char), len, f);
fclose(f);
f = fopen("c:\\test1.txt", "w");
fwrite(p, sizeof(char), len, f);
fclose(f);
delete[] p;
可惜结果仍然没变。这就比较奇怪了。怎么会出现这种情况呢?明明文件
大小为3,为何写到另外一个文件中去却变成了4呢?于是在程序读出test.txt
文件内容的下一行添加了一条语句:
for(int i = 0; i < len; i++)
cout << (int)p[i];
结果在屏幕上显示的居然是这个结果:46 10 0。居然没有把0A输出。而是
输出了0。我突然想到fread返回的结果是真正读到数据p中的长度,于是我又改
变了一下上面的程序,将fread的结果打印出来:
cout << fread(p, sizeof(char), len, f) << endl;
结果果然是2,而不是想当然的3。原来在window下,回车换行的两个字符读到
一个数组中去时,只会在数组中保存一个字符:0D。但是用feek来计算文件长
度时返回的却是文件的实际大小,而不是真正读入到数组中的值。
于是,采用fstream类来写入的时候,文件中每多一个回车换行,实际用
read函数读到字符数组中的个数就减少一个。而前面我仍然用文件长度来将读
到字符数组中的内容写到某个文件中去时,显然会多写入一些字符。而这些多
写入的字符值由于一开始用memset置为0,所以最后在test1.txt文件中就多了
几个值为0的字符。
显然,用fstream类是无法解决这个问题的。因为它没法返回真正读到字符
数组中的个数。所以当写回文件时会多写入字符。除非在读文件时判断有多少
回车换行符,从而在总文件大小中减去这部分值,才是真正读到字符数组中的
值。所以,解决这个问题只能使用fread函数,因为该函数提供了一个返回参数
来告知真正读到字符数组中的字符个数(或者使用window提供的API:ReadFile)
该函数也同样提供了一个返回参数。
因此,在window下读出一个文件时,遇到回车换行两个字符,只会读入一个
字符:0A。以后在处理时,只能判断是否是0A来判断换行,而不能判断0d来判断
是否换行。而读出文件的真正大小需要用fread函数来得知。