【问题标题】:C++ Read Binary file containing numbers of type doubleC++ 读取包含 double 类型数字的二进制文件
【发布时间】:2011-06-28 11:20:52
【问题描述】:

我有一个包含 double 类型数字的二进制文件。
示例输入文件可在此处获得:www.bobdanani.net/download/A.0.0
我想阅读文件并打印其中的数字。 这就是我所做的:

char* buffer;
int length;
string filename = "A.0.0";
ifs.open (filename.c_str(), ios::in | ios::binary);
// get length of file:
ifs.seekg (0, ios::end);
length = ifs.tellg();
ifs.seekg (0, ios::beg);
// allocate memory:
buffer = new char [length];
// read data as a block:
ifs.read (buffer,length);
ifs.close();

cout.write (buffer,length);
cout << buffer << endl;

delete[] buffer;

我也尝试在打印数字时使用类型转换来加倍,但我得到了奇怪的字符。做这个的最好方式是什么?我需要这个二进制文件的数据作为并行程序函数的输入。但这超出了这个问题的范围。

【问题讨论】:

  • 也许你需要在使用之前初始化缓冲区,就像这样:memset(buffer, 0, length)
  • 如果不知道文件中双精度的格式,就不可能回答这个问题。 “二进制”不是一种格式;二进制双精度可以有许多不同的格式。
  • 另外,binary 文件不太可能通过 text 字符(例如空格/制表符)来分隔值。为什么还要分开?
  • 嘿,抱歉,我已更正问题并发布包含示例输入文件的链接。抱歉,我可能对制表符分隔格式有误。只是当我在 bash 上使用 ( od - e 文件名 ) shell 命令打印值时,它会以制表符分隔格式打印值。

标签: c++ binaryfiles ifstream readfile


【解决方案1】:

虽然我可能是错的,因为你说数字由制表符/空格分隔,我愿意这实际上是 ASCII 数据,而不是原始二进制数据。因此,处理浮点值的最佳方法是在ifstream 对象上使用operator&gt;&gt;,然后将其推入double。这会将输入值自动转换为双精度值,因为您所做的只会复制组成浮点值的字符字节,但它们本身不是浮点值。另外,如果您尝试像字符串一样输出缓冲区,则您没有明确地以空值终止它,因此它将继续读取堆栈,直到遇到空值终止符或由于访问内存而导致分段错误操作系统不允许您访问堆栈顶部。但无论哪种方式,最终,您的缓冲区都不会是 double 数据类型的表示。

所以你会有类似的东西:

double my_double_val;

ifs.open (filename.c_str());

if (ifs)
{
    ifs >> my_double_val;
}
else
{
    cerr << "Error opening file" << endl;
}

ifs.close();

cout << "Double floating point value: " << my_double_val << endl;

【讨论】:

  • 他说愿意打赌是文本数据
  • 是的,并且由于 OP 提到他的数字由制表符/空格分隔,这听起来不像“二进制”数据,而更像是 ASCII 数据,我猜这可能会被误解作为二进制数据,因为 ASCII 也只是一系列字节。我只是从未听说过需要制表符/空格分隔符的二进制格式...
  • @Jason:这是有原因的:双精度的 IEEE 二进制编码包含 (0x20) 空格或 (0x09) 制表符的可能性很大(每个存储的双精度约为 6%)作为 8 个字节之一。具有含糊含义的字符不会形成有用的文件格式。
  • 嘿,抱歉,我已更正问题并发布包含示例输入文件的链接。抱歉,我可能对制表符分隔格式有误。只是当我在 bash 上使用 ( od - e 文件名 ) shell 命令打印值时,它会以制表符分隔格式打印值。
  • 嗯,最简单的事情是,如果该命令为您提供所需的数字,则使用命令行,将od 的输出通过管道传输到您的程序中,然后从@ 读取987654327@。例如,您可以使用od -e filename | my_c_plusplus_prog,在您的程序中,只需将operator&gt;&gt;std::cin 一起使用,然后执行cin &gt;&gt; int_index &gt;&gt; double1 &gt;&gt; double2; 之类的操作,其中index 是一个整数,而double1double2是浮点值。至少当我在您的文件上运行od 时,它似乎正在输出这种格式。
【解决方案2】:
cout.write (buffer,length);

不要这样做!以上是将二进制数据转储到标准输出。

cout << buffer << endl;

也不要这样做!以上将二进制数据转储到标准输出的第一个字节,该字节恰好为零。如果没有这样的字节,这将继续超过缓冲区的末尾(所以未定义的行为)。

如果缓冲区确实包含双打,而且只有双打,你可以做一些讨厌的事情,比如

double * dbuf = reinterpret_cast<double*>(buffer);
int dlength = length / sizeof(double);

【讨论】:

    【解决方案3】:

    在 C++ 中使用系统函数调用(假设您使用的是 unix OS)并将'od -e filename' 作为系统函数调用的参数传递。然后您可以轻松地管道它返回的值并读取它们。这是一种方法。当然,还有很多其他方法可以做到这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-26
      • 2014-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-01
      • 2011-09-03
      • 2016-01-15
      相关资源
      最近更新 更多