2

我正在学习 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。我想这是关于文件结尾的问题,但我无法解决问题。

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

非常感谢,

马可

4

3 回答 3

4

fstream::get返回一个int- 值。这是问题之一。

其次,您正在阅读binary,因此您不应该使用格式化的流。你应该使用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;
}
于 2013-05-08T07:48:36.180 回答
2

这不是istream::get()设计使用的方式。使用此功能的经典习惯用法是:

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

甚至更惯用:

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

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

不过,据我所知,您提供的代码应该可以工作。这不是惯用语,也不是

如果读取的字符值为负,C++ 标准不清楚它应该返回什么。 fgetc()需要 range 中的值[0...UCHAR_MAX],我认为可以安全地假设这是这里的意图。至少,我使用的每个实现都是这样做的。但这不会影响您的输入。根据实现对标准的解释方式, 的返回值in.get()必须在 或 范围内 [0...UCHAR_MAX][CHAR_MIN...CHAR_MAX]或者必须是 EOF(通常为 -1)。(我相当确定其意图是要求[0...UCHAR_MAX]的原因是因为否则,您可能无法将文件结尾与有效字符区分开来。)

如果返回值为 EOF(几乎总是 -1),failbit则应该设置,所以in.good()return false。在任何情况下in.get()都不允许返回 221497852。对于您的结果,我可能想到的唯一解释是您的文件有一些字符,文件末尾设置了第 7 位,该实现返回一个负数this(但不是文件结尾,因为它是一个字符),这会导致 in 的索引越界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 的代码集。两者都差不多,但在今天还不是很普遍。)

于 2013-05-08T08:24:20.763 回答
-1

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

向所有问我的人干杯,

马可

于 2013-05-08T17:04:54.800 回答