我有以下简单代码,它将文本文件的内容读入字符数组:
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位。
答案 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
需要包含两个不同的
信息:在文件中寻找的位置,以及有关的信息
这个州。我不认为有任何状态依赖多字节
然而,今天广泛使用的编码。)