C ++以二进制模式读取文件。文件结尾的问题

时间:2013-05-08 07:38:37

标签: c++ linux io binaryfiles

我正在学习C ++,我必须以二进制模式读取文件。这是我的方式(遵循C ++参考):

unsigned values[255];
unsigned total;
ifstream in ("test.txt", ifstream::binary);

while(in.good()){
    unsigned val = in.get();
    if(in.good()){
        values[val]++;
        total++;
        cout << val <<endl;
    }
}

in.close();

所以,我正在读取每个字节的文件字节,直到in.good()为真。我在cout的末尾放了一些while以了解发生了什么,这是输出:

marco@iceland:~/workspace/huffman$ ./main 
97
97
97
97
10
98
98
10
99
99
99
99
10
100
100
10
101
101
10
221497852
marco@iceland:~/workspace/huffman$

现在,输入文件“test.txt”只是:

aaaa
bb
cccc
dd
ee

所以一切都很完美,直到最后,那里有221497852.我猜这是关于文件结尾的东西,但我无法解决问题。

我正在使用gedit&amp;在debian机器上的g ++(64位)。 任何帮助将不胜感激。

非常感谢,

3 个答案:

答案 0 :(得分:3)

fstream::get会返回int - 值。这是其中一个问题。

其次,您正在阅读二进制,因此您不应使用格式化的流。您应该使用fstream::read

// read a file into memory
#include <iostream>     // std::cout
#include <fstream>      // std::ifstream

int main () {

  std::ifstream is ("test.txt", std::ifstream::binary);
  if (is) {
    // get length of file:
    is.seekg (0, is.end);
    int length = is.tellg();
    is.seekg (0, is.beg);

    char * buffer = new char [length];

    std::cout << "Reading " << length << " characters... ";
    // read data as a block:
    is.read (buffer,length);

    if (is)
      std::cout << "all characters read successfully.";
    else
      std::cout << "error: only " << is.gcount() << " could be read";
    is.close();

    // ...buffer contains the entire file...

    delete[] buffer;
  }
  return 0;
}

答案 1 :(得分:1)

这不是istream::get()设计使用的方式。 使用这个函数的经典习语是:

for ( int val = in.get(); val != EOF; val = in.get() ) {
    //  ...
}

或甚至更惯用:

char ch;
while ( in.get( ch ) ) {
    //  ...
}

第一个循环实际上是从C继承的,其中in.get()是 相当于fgetc()

尽管如此,据我所知,您提供的代码应该工作。 这不是惯用的,它不是

C ++标准尚不清楚它应该返回什么 读取的字符值为负数。 fgetc()需要输入值 范围[0...UCHAR_MAX],我认为可以安全地假设 这是 intent 。它至少是每一个 我用过的实现。但这不会影响你的 输入。取决于实现如何解释 标准,in.get()的返回值必须在范围内 [0...UCHAR_MAX][CHAR_MIN...CHAR_MAX],或者必须是EOF (通常为-1)。 (我很确定意图的原因 要求[0...UCHAR_MAX]是因为否则,你可能不会 能够区分文件末尾和有效字符。)

如果返回值是EOF(几乎总是 -1),failbit应该设置,因此in.good()将返回 false。有的情况允许in.get() 返回221497852.我能想到的唯一解释 对于您的结果是您的文件有一些字符 第7位设置在文件的末尾,实现是 为此返回一个负数(但不是文件末尾, 因为它是一个字符),导致越界 values[val]中的索引,以及此超出范围的索引 不知何故最终修改val。或者你的实现是 已损坏,并且在返回结束时未设置failbit 文件。

可以肯定的是,我有兴趣知道你从中获得了什么 以下内容:

std::ifstream in( "text.txt", std::ios_base::binary );
int ch = in.get();
while ( ch != std::istream::traits_type::eof() ) {
    std::cout << ch << std::endl;
    ch = in.get();
}

这可以避免任何可能无效的索引和任何类型的问题 转化(虽然转化intunsigned很好 定义)。此外,出于好奇(因为我只能访问VC ++ 在这里,您可以尝试按以下方式替换in

std::istringstream in( "\n\xE5" );

我希望得到:

10
233

(假设8位字节和基于ASCII的代码集。两者都有 这几乎是,但今天不太普遍。)

答案 2 :(得分:-1)

我最终想出来了。 显然,问题似乎不是由于任何代码。问题是gedit。它总是在文件末尾附加换行符。这也发生在其他编辑器上,例如vim。对于某些编辑器,这可以配置为不附加任何内容,但在gedit中,这显然是不可能的。 https://askubuntu.com/questions/13317/how-to-stop-gedit-gvim-vim-nano-from-adding-end-of-file-newline-char

欢迎所有问我的人,