【问题标题】:Is istream::seekg with ios_base::end reliable?istream::seekg 和 ios_base::end 可靠吗?
【发布时间】:2014-05-31 15:50:38
【问题描述】:

假设我使用这种方式创建了一个文件:

std::ofstream osf("MyTextFile.txt");
string buffer="spam\neggs\n";
osf.write(buffer,buffer.length());
osf.close();

当我尝试使用以下方式读取该文件时,我意识到读取的字符多于当前字符。

std::ifstream is("MyTextFile.txt");
is.seekg (0, is.end);
int length = is.tellg();
is.seekg (0, is.beg);

char * buffer = new char [length];
is.read (buffer,length);

//work with buffer

delete[] buffer;

例如,如果文件包含 spam\neggs\n,则此过程读取 12 个字符而不是 10 个字符。前 10 个字符是 spam\neggs\n,正如预期的那样,但还有 2 个字符具有整数值 65533。 此外,仅当文件中存在\n 时才会出现此问题。例如,如果文件包含spam\teggs\t,则没有问题。

问题是; 我做错什么了吗?或者这个程序没有按应有的方式工作?

Bonus Q:你能推荐一个一次性读取整个文件的替代方法吗?

注意:我是这样找到的here

【问题讨论】:

    标签: c++ c++11 file-io io


    【解决方案1】:

    问题是你写的字符串

    "spam\neggs\n"
    

    最初为ofstream,而不在open(或在初始化器上)设置std::ios::binary标志。这会导致运行时转换为“本机文本格式”,即。例如,将输出上的每个 \n 转换为 \r\n(就像在 Windows 操作系统上一样)。所以,写完之后,你的文件内容其实是:

    "spam\r\neggs\r\n"
    

    (即 12 个字符)。 那个是由

    返回的
    int length = is.tellg();
    

    但是,当你尝试read 12 字符时,你得到了

    "spam\neggs\n"
    

    返回,因为运行时将每个 \r\n 转换回 \n

    作为最后的建议,,请不要使用new char[length]...使用std::stringreserve,这样您就不会泄漏内存等。如果您的文件可能非常大,也许一次slurp整个文件到内存也不是一个好主意。

    【讨论】:

      【解决方案2】:

      只是一个想法,因为数字 2 对应于 \ns 的计数:您是在 Windows 上执行此操作吗?它可能与实际包含\r\n 的文件有关。如果以二进制模式 (std::ios::binary) 打开文件会怎样?

      【讨论】:

      • 是的,我在 Windows 上,但我没有手动将结束行写入文件,而是使用 ostreamspam\neggs\n 写入文件。我也会用二进制模式检查
      • @SweeneyTodd : 如果ostream 没有以二进制模式打开,那么它会为你添加\rs
      • @ildjarn 是的,那个。我想发帖,但 SO 不会让我发帖。 ofstream 不带二进制模式转换为平台原生格式。
      • 好的,但是,它与is.seekg (0, is.end) 有什么关系?该 seekg 函数超出范围(到第 12 个字符)而不是第 10 个字符,对吗?
      • 是的,但是当您读取字符时,它会将输入文件上的每个\r\n 转换为\n,因此是十个字符。概括一下:您将spam\neggs\n 写入非二进制ofstream,文件的内容为spam\r\neggs\r\n(12 个字符)。当您使用非二进制 ifstream 重新打开同一个文件时,tellg 会返回该值。然后你读取内容,它会读取spam\neggs\n(因为ifstream 不是二进制的)。 ANYWAY,如果你只是用std::ios::binaryboth来读写,那么你就不会再有这种问题了。
      【解决方案3】:

      您能否建议一次读取整个文件的替代方法?

      是的:

      std::ifstream is("MyTextFile.txt");
      std::string str( std::istreambuf_iterator<char>{is}, {} ); // requires <iterator>
      

      str 现在包含该文件。这能解决您的问题吗?

      【讨论】:

      • 感谢您展示另一种方式,但我真正想知道的是我使用的方式有什么问题
      猜你喜欢
      • 1970-01-01
      • 2014-02-07
      • 2012-12-29
      • 2011-03-30
      • 2012-08-28
      • 2011-06-19
      • 2012-03-05
      • 2013-01-18
      相关资源
      最近更新 更多