一个有关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函数来得知。
     

你可能感兴趣的:(ios,c,api,File,delete,语言)