从标准输入流(std::cin)读取二进制数据

19

如何最简单地从 std::cin 读取二进制(非格式化)数据并将其存储到 stringstringstream 中?


为什么不在二进制模式下使用“/dev/stdin”打开ifstream? - user142019
3
@WTP 只能在 Unix 上运行。 - Jonathan Sternberg
1
还可以参考使用std::freopen的讨论(但它看起来有点hacky)。如果有人能提供Linux、OS X、Solaris和Windows的示例,那就太好了。 - jww
7个回答

11

9

1
终于可以在Windows上工作了! _setmode(_fileno(stdin), _O_BINARY);vector<char> v(static_cast<size_t>(len), 0); cin.read(&v[0], len);。 你需要包含 fcntl.hio.h 来实现这个功能。 - fmuecke

2

所有预定义的 iostream 对象都必须绑定到相应的 C 流:

对象 cin 控制着与对象 stdin 关联的流缓冲区的输入,声明在 <cstdio> 中。

http://eel.is/c++draft/narrow.stream.objects

因此,获取二进制数据的方法与 C 相同:

基本上,你真正能做的最好的事情是这样:

freopen(NULL, "rb", stdin);

这将重新打开标准输入,但采用二进制模式。在普通模式下,在 Windows 上从 stdin 读取将把 \r\n(Windows 换行符)转换为单个字符 ASCII 10。使用“rb”模式禁用此转换,以便您可以正确地读取二进制数据。

https://dev59.com/wXI-5IYBdhLWcg3w8dYQ#1599093


2
在Unix/POSIX系统中,您可以使用cin.get()方法逐字节读取并将数据保存到容器中,例如std::vector<unsigned int>,或者您可以使用cin.read()来读取固定数量的字节到缓冲区中。还可以使用cin.peek()检查是否有任何数据流结束指示符。
请注意避免在此类操作中使用operator>>重载...使用operator>>会导致在观察到分隔符字符时发生中断,并且它还将从流本身中删除分隔符字符。这将包括任何等效于空格、制表符等的二进制值。因此,使用该方法从std::cin存储的二进制数据将无法逐字节匹配输入二进制流。

4
cin 仍处于文本模式。这对于类Unix系统可能不重要,但在Windows上,例如,每个 CR LF 行尾将仍被转换为单个 '\n' 字符。 - Keith Thompson

2

cin.read会存储一定数量的字节,没有逻辑搜索@Jason提到的分隔符类型。

但是,仍然可能存在在流上活动的转换,例如CRLF -> NL,因此对于二进制数据仍不理想。


0

在Windows/Mingw/MSYS/Bash中,如果您需要在不同的命令之间使用二进制流进行管道传输,则需要将std :: cin和std :: cout作为二进制流进行操作。

Mikhail提供的_setmode解决方案非常完美。

使用MinGW,所需的头文件如下:

#include <io.h>
#include <fcntl.h> 

0

cplusplus.com:

未格式化的输入 istream 类的其他大多数成员函数用于执行未格式化输入,即不对从输入获取的字符进行解释。这些成员函数可以从输入字符序列中获取确定数量的字符(get, getline, peek, read, readsome)...... 正如 Lou Franco 指出的那样,std::cin 没有使用 std::ios_base::binary 打开,但其中一个函数可以让您接近您正在寻找的行为。

2
“可能会让你接近”:它也可能会给你带来麻烦,因为操作系统/库有权进行行尾转换,这可能会损坏您的二进制数据。我不确定您是否已经从'read'/'readsome'甚至直接从*rdbuf()(流缓冲区)中读取,而没有进行过这种转换。 - sehe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接