Ifstream从文本文件中读取错误的字符

Ifstream reads wrong characters from text file

本文关键字:取错误 字符 读取 文本 文件 Ifstream      更新时间:2023-10-16

我有以下简单的代码,它将文本文件的内容读取为字符数组:

const char* name = "test.txt";
std::cout << "Loading file " << name << std::endl;
std::ifstream file;
file.open(name);
file.seekg (0, std::ios::end);
int length = file.tellg();
std::cout << "Size: " << length << " bytes" << std::endl;
file.seekg (0, std::ios::beg);
char* buffer = new char[length];
file.read(buffer,length);
file.close();
std::cout.write(buffer,length);

然而,ifstream似乎从文件中读取了错误数量的字符:每行增加1个字符。我在网上搜索了一下,在win7中,除了每行末尾的换行符(\n)之外,文本文件似乎还有回车符(\r)。但是,流在某种程度上看不到这些\r,但仍然使用文件中的原始符号数,从文件末尾以外读取额外的字节。有可能以某种方式解决这个问题吗?

如果有帮助的话:我使用MinGW编译器和Windows7 64位。

您可能希望以二进制模式打开文件:

file.open(name, ios_base::in | ios_base::binary);

否则,标准库会将每个Windows换行符(CR+LF)转换为单个n

这意味着可以从文件中读取的字符数与文件的大小不同。当您调用read()时,它会读取尽可能多的字符。如果它不能读取您请求的字符数,它会设置流的failbit

您从一些非常错误(但广泛)的观点开始。file.tellg()不返回int;它返回一个实现定义了类型为streampos的对象,该对象必须是类类型,并且可以或者可以不转换为积分型。如果是可转换为积分类型(我不知道有什么实现如果没有,即使不需要),也不能保证得到的整数表示的不仅仅是一个神奇的cookie将允许重新设置到相同的位置。

在实践中,这可能不是现代机器的大问题:两者Unix和Windows返回从文件开始的偏移量(以字节为单位)。在Unix的情况下,这很好,因为内部表示对外部表示是一对一。在这种情况下在Windows中,有一个换行符的重映射:在文本文件中,一行结束是0x0D、0x0A的两字节序列,当读取时,单个字符CCD_ 7。和streampos(转换为积分型)以字节为单位给出文件中必须查找的位置的偏移量,而不是要到达该位置,必须读取的字符数。对于事物就像你正在做的事情一样,这不是问题;分配的缓冲区可能比需要的大一点,但永远不会太大小的

请注意,在大型机上可能不是这样。历史上至少,大型机使用了面向块的文件streampos可以很容易地分解为字段块号的特定位数,字节的其他位数块中的偏移。根据这些在单词中的布局方式,这样分配的缓冲区很容易达到几个数量级太大,或者如果偏移被放置在高位,则太小。

获得所需缓冲区确切大小的唯一可靠方法是依赖于系统,在某些系统(包括Windows)上,可能存在除了阅读所有字符并数数之外,别无选择。

(CCD_ 10被要求为类类型的原因是,历史上,许多较老的多字节编码都有编码状态;你在不知道字符的情况下无法正确解码字符因此streampos需要包含两个不同的信息:要在文件中查找的位置,以及有关这种状态。我不认为存在任何依赖于状态的多字节然而,如今广泛使用的编码。)

阅读有关打开binary读取文件的信息(谷歌或查看此处)。