【问题标题】:Reading binary files with null bytes in them with C++使用 C++ 读取包含空字节的二进制文件
【发布时间】:2013-07-04 05:45:18
【问题描述】:

执行此操作的规范方法是什么?

我必须在这里阅读wstring,但我确信答案也应该适用于string

这是我现在正在尝试的:

wifstream file(filename, ios::in | ios::binary);
// this next line is cleverer but works the same way (i.e. null byte stops it)
// return wstring(istreambuf_iterator<wchar_t>(file), istreambuf_iterator<wchar_t>());
wstring out;
wchar_t buf[8192];
while (true) {
    file.read(buf, 8192);
    streamsize len = file.gcount();                                       
    cerr << len << "chars read.";                                         
    out.append(buf, len);                                                 
    if (len != 8192) break;                                               
}                                                                         
return out;

如何在文件中遇到空字节时让它继续读取?

如果 POSIX 有一项法令禁止任何文件中存在空字节,我实际上不会感到惊讶。但显然 Vim 正在使用一些魔法将所有这些空值写入撤消文件格式。此外,如果您碰巧将内容编码或加密为随机字节流(或多种模拟采样),则必须产生空值。我的意思是,我可以继续:OS X 上的管道 (FIFO) 可以很好地处理通过它们的空字节:我可以 cat 撤消文件,将其通过管道传输到 xxd,它可以读取它。

这显然是我遇到的一些简单的事情。它是什么?当然有一种 C++ 方法可以做到这一点。或者也许你知道&lt;stdio.h&gt; 的方法。我想知道。

例如,这是我正在测试的文件:

% cat .dmp.cpp.un\~| xxd | head                                   
0000000: 5669 6d9f 556e 446f e500 0218 96c6 25f6  Vim.UnDo......%.
0000010: 64bb 2301 6ed8 3578 5c50 61e0 eae5 a819  d.#.n.5x\Pa.....
0000020: b17d 53b5 f932 dc9d 40aa 1b00 0000 8500  .}S..2..@.......
0000030: 0000 5720 2020 2020 2020 2020 2020 2063  ..W            c
0000040: 6572 7220 3c3c 2022 466f 756e 6420 616e  err << "Found an
0000050: 2075 6e70 7269 6e74 6162 6c65 2063 6861   unprintable cha

字节 2b 是第一个空字节。程序读取了 44 个字节 (2c),因此它写入了第一个空字节,并停在那里。

% la .dmp.cpp.un\~
-rw-r--r--  1 lust  staff  326836 Jul  4 01:41 .dmp.cpp.un~

P.S.,我在 here 的评论中得到了简洁的单行字。可悲的是,它也受到这个问题的影响。

【问题讨论】:

  • 您如何验证它不是?打印字符串将在第一个\0 处停止,但数据可能仍在字符串中。检查std::string::size() 可能吗?
  • 好吧,对于初学者来说,当我在我的 vim undofile 上运行它时,它有很多 KB,它只读取 44 个字节(我是 cerring gcount 给我的东西......)。我xxd文件,果然第44个字节是\0
  • 我有同样的字符串没有任何问题:while (file.read(buf, sizeof(buf)).gcount() > 0) rep.append(buf, file.gcount()) ;
  • 这段代码对我有用。我怀疑可能是您在返回字符串后如何使用它。
  • 我不需要对字符串做任何事情!! gcount 比实际实际大小要小得多!如果你们能用相同的程序让它读取任何空字节,请给我看截图或其他东西。

标签: c++ file-io filestream binaryfiles ifstream


【解决方案1】:

我首先使用常规字符串解决了这个问题。

ifstream file(filename, ios::in | ios::binary);
wstring out;
char buf[8192];
while (true) {
    file.read(buf, 8192);
    streamsize len = file.gcount();
    cerr << len << "chars read.";
    string s(buf, len);
    out.append(s.begin(), s.end());
    if (len != 8192) break;
}
return out;

【讨论】:

    【解决方案2】:

    根本原因是wstring 不保存字节,而是宽字符。显然需要在字节和(宽)字符之间进行转换。就是这个翻译坏了。

    如果您想从二进制文件中读取字节,请将它们读入适当的容器中。例如。 std::vector&lt;unsigned char&gt;。如果您想从文本文件中读取(宽)字符,请继续使用当前代码。但是,将它们混合是一个问题。

    (这个建议适用于许多系统,即使它们可能会在不同的地方显示问题。特别是 Unix 在 ASCII 文本文件和二进制文件之间几乎没有区别,而 Windows 的 Unicode(UTF-16)问题往往较少文本文件及其在内存中的表示。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-06
      • 1970-01-01
      • 2011-07-26
      • 2014-01-26
      • 1970-01-01
      • 1970-01-01
      • 2011-02-03
      相关资源
      最近更新 更多