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

时间:2012-01-12 10:55:12

标签: c++ io

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

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编译器和Windows 7 64位。

3 个答案:

答案 0 :(得分:6)

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

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

否则会发生的情况是标准库会将每个Windows换行符(CR + LF)转换为单个\n

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

答案 1 :(得分:0)

了解binary阅读的开放文件(谷歌或查看here)。

答案 2 :(得分:0)

你从一些非常错误(但很普遍)的观点开始。 file.tellg()不会返回int;它返回一个实现 类型为streampos的已定义对象,它必须是类类型,并且可以 或者可能无法转换为整体类型。如果是的话 可转换为整数类型(我不知道实现 如果不是,即使不是必需的,也不能保证 结果整数表示的不仅仅是一个神奇的cookie 允许转到同一位置。

在实践中,这可能不是现代机器上的一个大问题:两者兼而有之 Unix和Windows从文件的开头返回以字节为单位的偏移量。 在Unix的情况下,这工作正常,因为映射的 对外部的内部表示是一对一的。在这种情况下 对于Windows,有一个重新映射的行结尾:在文本文件中,一行 结束是一个0x0D,0x0A的双字节序列,当读取时, 单个字符'\n'。并streampos(转换为整数类型) 给出你必须在文件中搜索的位置的字节偏移量,而不是 你必须阅读才能到达那个位置的char数量。为了这些事 就像你似乎在做什么,这不是问题;分配的 缓冲区可能比必要的大一点,但它永远不会 小。

请注意,这可能不适用于大型机。从历史上看,在 至少,大型机使用面向块的文件,以及a的整数值 streampos很容易被分解成字段,有一个 块号的特定位数,以及字节的其他位 块中的偏移量。取决于这些词的排列方式, 像你一样分配的缓冲区可能很容易达到几个数量级 太大,或者如果偏移位置在高位上,则太小。

获得所需缓冲区大小的唯一可靠方法是 系统依赖,并在某些系统(包括Windows),可能有 除了通过阅读所有角色并计算它们之外别无他法。

streampos必须是类类型的原因是因为, 历史上,许多旧的多字节编码都具有编码状态;您 在不知道什么字符的情况下无法正确解码字符 在它之前。所以streampos需要包含两个不同的 信息:在文件中寻找的位置,以及有关的信息 这个州。我不认为有任何状态依赖多字节 然而,今天广泛使用的编码。)