【问题标题】:Reading binary data from stdin从标准输入读取二进制数据
【发布时间】:2011-02-20 12:12:42
【问题描述】:

是否可以在 Python 2.6 中将标准输入读取为二进制数据?如果有,怎么做?

我在Python 3.1 documentation 中看到这相当简单,但在 2.6 中执行此操作的工具似乎不存在。

如果3.1中描述的方法不可用,有没有办法关闭stdin并以二进制模式重新打开?

更新

为了清楚起见,我在 MS-DOS shell 中使用“类型”将二进制文件的内容通过管道传输到我的 python 代码。据我了解,这应该相当于 Unix 的“cat”命令。但是当我对此进行测试时,我总是比预期的文件大小少一个字节。

更新 #2

首先,感谢所有的答案。我正在慢慢地努力寻找一个真正可用的解决方案。最后,我仍在尝试构建一个自包含的 JAR 文件,该文件执行我的 Python 代码,自动传递所有未受污染的命令行参数。

我选择 Java/JAR/Jython 路线的原因是因为我的主要外部库之一只能作为 Java JAR 使用。但不幸的是,我是从 Python 开始的。不久前将我的代码转换为 Java 可能更容易,但由于这些东西都应该是兼容的,我想我会尝试通过它来证明它可以完成。

如果有人想知道,这也与我前几天问的问题有关。

Packaging and deploying a Jython program from Eclipse

question 回答了其中的一些问题。

因此,我将尝试更新我的原始问题,并添加一些关于我目前所了解的内容的注释。

【问题讨论】:

    标签: python python-2.x


    【解决方案1】:
    import sys
    
    data = sys.stdin.read(10) # Read 10 bytes from stdin
    

    如果您需要解释二进制数据,请使用struct 模块。

    【讨论】:

    • 如果我随后调用不带参数的 sys.stdin.read(),它应该读取通过管道输入的所有二进制数据,对吗?那么如何正确确定长度?如果数据的最后一个字节为零,则 len(data) 返回不正确的值。您如何检查和纠正这种情况?
    • len 计算字符串中的 \x00 个字符。 Python 没有以 null 结尾的字符串。 len("Hello\x00") == 6
    • 我想知道是否是 MS-DOS shell 的“type”命令导致了最后一个字节的丢失?我想我将不得不在 Linux 上测试等价物。谢谢。
    • 我认为这个答案错过了问题的重点:如果流处于“文本”模式,read() 的结果可能与流处于“二进制”模式时不同。
    • 它可能会损坏 Windows 上的输入流,例如 '\r\n' -> '\n'。此外,在 Python 3 上,sys.stdin.read() 返回 Unicode 字符串,例如,b'\xf0\x9f\x96\x96' -> '\U0001f596'(4 个字节 -> 1 个字符)。如果输入不是文本,这是不受欢迎的行为。
    【解决方案2】:

    使用-u command line switch 强制 Python 2 将 stdin、stdout 和 stderr 视为二进制无缓冲流。

    C:> type mydoc.txt | python.exe -u myscript.py
    

    【讨论】:

    • 我已经用 'type' 对此进行了测试,它似乎可以工作。也就是说,如果我省略 -u 标志,每行会少一个字符。
    • 根据文档,设置 PYTHONUNBUFFERED 环境变量将具有相同的效果。不确定这是否有帮助。
    • 更简单的是,您似乎需要做的就是: sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0) 这将重新打开无缓冲的 fd “二进制”模式。
    • @thebeav:奇怪的是,这在我的系统上不起作用。我不知道这是因为我使用的是 CPython 而不是 Jython,还是因为我运行的是 Windows XP Pro,并且“类型”的行为不同,或者是因为马纳萨斯地区的磁异常导致计算机做不同的事情。 FWIW,我尝试了多种方法让 Python 在解释器启动后更改文件模式,包括通过 ctypes 访问 C 运行时的“setmode”函数。没有什么对我有用。
    • 呃-哦。我闻到了便携性问题。谢谢(你的)信息。我想我将不得不在多个平台上进行一些相当严格的测试。我希望这与使用的 JVM 无关。
    【解决方案3】:

    如果你还需要这个... 这个简单的测试我用来读取包含 0x1A 字符的二进制文件

    import os, sys, msvcrt
    
    msvcrt.setmode (sys.stdin.fileno(), os.O_BINARY)
    s = sys.stdin.read()
    print len (s)
    

    我的测试文件数据是:

    0x23, 0x1A, 0x45
    

    如果不将标准输入设置为二进制模式,此测试会在将 0x1A 视为 EOF 时立即打印 1。 当然它只适用于 windows,因为依赖于 msvcrt 模块。

    【讨论】:

    • 但是 Windows 是唯一一个大多数人都会遇到问题的系统,所以这应该是一个可以接受的解决方案。
    • 这是 Python 2 在 Windows 上从标准输入检索原始字节的正确解决方案。在 Unix 上,二进制模式和普通模式没有区别。看到这个帖子:code.activestate.com/lists/python-list/20426(以原始(二进制)模式重新打开标准输入?)
    • 我在 Windows 上遇到了一个ValueError: insecure string pickle 异常,当我试图取消pickle 在一个进程中写入stdout 的数据时,该进程正在通过管道传输到另一个进程中。解决方案原来是在写入数据的过程中添加msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    【解决方案4】:

    来自文档(参见here):

    标准流处于文本模式 默认。写入或读取二进制 数据到这些,使用底层 二进制缓冲区。例如,要写 字节到标准输出,使用 sys.stdout.buffer.write(b'abc').

    但是,正如在接受的答案中一样,使用-u 调用 python 是另一种强制标准输入、标准输出和标准错误完全无缓冲的选项。有关详细信息,请参阅 python(1) 手册页。

    有关文本缓冲的更多信息,请参阅documentation on io,并使用sys.stdin.detach() 在 Python 中禁用缓冲。

    【讨论】:

    • 该文档导致 py3k 文档,而不是 OP 想要处理的内容。
    • 我用 Python v3.2.5 尝试过-u,但它没有任何用处。但是使用sys.stdout.buffer 效果很好,尽管在 Python 2.7.8 上没有这样的功能。
    • OP 的问题是关于 Python 2.6。
    【解决方案5】:

    这是 Linux/Windows Python 2/3 兼容代码从标准输入读取数据而不会损坏的最终剪辑:

    import sys
    
    PY3K = sys.version_info >= (3, 0)
    
    if PY3K:
        source = sys.stdin.buffer
    else:
        # Python 2 on Windows opens sys.stdin in text mode, and
        # binary data that read from it becomes corrupted on \r\n
        if sys.platform == "win32":
            # set sys.stdin to binary mode
            import os, msvcrt
            msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
        source = sys.stdin
    
    b = source.read()
    

    【讨论】:

      【解决方案6】:

      您可以通过以下方式执行无缓冲读取:

      os.read(0, bytes_to_read)

      0 是标准输入的文件描述符

      【讨论】:

        猜你喜欢
        • 2010-12-08
        • 2012-11-14
        • 1970-01-01
        • 1970-01-01
        • 2015-11-23
        • 2015-10-07
        • 2014-01-28
        • 1970-01-01
        • 2010-12-01
        相关资源
        最近更新 更多