【问题标题】:c++ binary file ioc++二进制文件io
【发布时间】:2012-01-11 00:55:39
【问题描述】:

在尝试修改我的逻辑以响应this 问题。我决定使用message-size + protobuf-object-after-SerializeToArray 对序列化协议缓冲区对象,(如果您不明白我在说什么,请不要担心)。无论如何我的实现不起作用。所以我决定看看 c++ fstream 是如何工作的。这是一场语义噩梦,我不确定是否需要在每次读取后(甚至可能在每次写入后)使用seekg 重新定位位置句柄。我只使用 write() 和 get() 方法。以下人为的程序失败了,为什么失败了,在这种情况下我需要 seekg 吗?

#include <fstream>
#include <boost/cstdint.hpp>
#include <iostream>

void write()
{
  boost::uint8_t one = (boost::uint32_t )255;
  boost::uint8_t two = (boost::uint32_t) 254;
  boost::uint8_t three =(boost::uint32_t) 253;

  std::fstream file("test", std::fstream::out | std::fstream::binary | std::fstream::trunc);

  file.write( (char *) &one, sizeof(one));
  file.write( (char *) &two, sizeof(two));
  file.write( (char *) &three, sizeof(two));

  std::cout << file.tellg() << std::endl;
  file.flush();
  file.close();
}

void read()
{
  boost::uint8_t one=0;
  boost::uint8_t two=0;
  boost::uint8_t three=0;

  std::fstream file("test", std::fstream::in | std::fstream::binary);


  file.get((char *) & one, sizeof(one)); 
  file.get((char *) & two, sizeof(two)); 
  file.get((char *) & three, sizeof(three)); 

  std::cout << file.tellg() << std::endl;

  std::cout << (boost::uint32_t) one << ":" << (boost::uint32_t) two  << ":" << (boost::uint32_t)three<< std::endl;
  file.close();
}


int main()
{
  write();
  read();  
}

输出是:

3
-1
0:0:0

C++ 二进制文件 io 让我感到悲伤和愚蠢:(

【问题讨论】:

  • boost::uint8_tunsigned char。要在std::cout 上输出值,您应该将其转换为int(或任何其他非字符整数类型)。
  • 是的,我也想通了,谢谢,更新了问题。
  • Hexdumping 结果文件给了我feff 00fd(请记住字节序:),所以至少写作部分似乎正在工作。
  • 使用调试器而不是依赖cout,并在read代码中的所有用法之后检查fstream状态。
  • @steve 调试器的原因是内存中的东西,而不是文件中的东西,或者库的逻辑使用问题? :D

标签: c++ stl io binary-data


【解决方案1】:

您应该使用istream::read,而不是istream::get

前者提取字符直到 (n - 1) 个字符被提取或找到分隔符。后者只是从文件中读取未格式化的数据。

【讨论】:

    【解决方案2】:

    fstream::get() 是针对文本量身定制的。它期望 size 参数说明缓冲区中的尾随 nul。通过sizeof(one) + 1 作为大小。它还将停止阅读'\n'。您可以更改被视为分隔符的字符,但您似乎不能使用“请不要分隔符”。如果您想要原始二进制数据,请使用fstream::read()

    读取单个字节时,也可以使用

    one = (boost::uint8_t) file.get();
    two = (boost::uint8_t) file.get();
    three = (boost::uint8_t) file.get();
    

    但这对于大小> 1的数据自然没有好处。您需要fstream::read()

    file.read((char *) & one, sizeof(one));
    file.read((char *) & two, sizeof(two));
    file.read((char *) & three, sizeof(three));
    

    结果:

    3
    3
    255:254:253
    

    【讨论】:

    • 天哪,回到 ansi-c 文件 IO 我猜:/,这是一个雷区。问题是我必须在协议缓冲区二进制字符串中写入并将大小作为二进制添加。我记得能够改变 cout 的行为以将整数打印为十六进制等,有没有办法让 fstream 表现得更笨? (即,没有任何形式的标记)?
    • Nono,我不太了解 c++ 标准库,总是使用 QT :P 使用 fstream::read(),就像 J. Calleja 说的那样。
    • 但这会导致在 stdlib/stl 代码中发生一些标记化 :(,我正在将文本文件预处理为二进制格式以摆脱文本处理 :D
    • 不,fstream::read() 不进行标记化。 fstream::get() 确实如此。
    • 感谢您的坚持 :D celt 首先做对了,而且他是新人,所以我会给他打勾 :D
    【解决方案3】:

    istream::get 不是用于二进制 I/O,而是用于文本 I/O。特别是,file.get(ptr, n) 读取一个 C 字符串,即最多只读取 n-1 个字符,然后以空值结尾。此外,如果您在流中遇到'\n'(不是您在二进制 I/O 中想要的),读取将停止。请注意,如果您正在检查流状态(在执行 I/O 时总是一个好主意),您会发现第一次读取尝试已经导致错误。

    您应该改用 readwrite 进行二进制 I/O(或者,直接使用相应的流缓冲区)。

    【讨论】:

      猜你喜欢
      • 2018-04-28
      • 2011-04-15
      • 1970-01-01
      • 2013-05-22
      • 1970-01-01
      • 1970-01-01
      • 2015-04-08
      • 2017-10-01
      • 2019-04-20
      相关资源
      最近更新 更多