【问题标题】:Python 2.x - Write binary output to stdout?Python 2.x - 将二进制输出写入标准输出?
【发布时间】:2014-11-09 20:25:13
【问题描述】:

有没有办法在 Python 2.x 中将二进制输出写入 sys.stdout?在 Python 3.x 中,您可以只使用 sys.stdout.buffer(或分离 stdout 等),但我无法找到 Python 2.5/2.6 的任何解决方案。

编辑,解决方案: 来自 ChristopheD 的链接,如下:

import sys

if sys.platform == "win32":
    import os, msvcrt
    msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)

编辑:我正在尝试将 PDF 文件(二进制形式)推送到标准输出,以便在 Web 服务器上提供服务。当我尝试使用 sys.stdout.write 写入文件时,它会将各种回车添加到导致 PDF 呈现损坏的二进制流中。

编辑 2:对于这个项目,不幸的是,我需要在 Windows Server 上运行,所以 Linux 解决方案已经出来了。

简单的虚拟示例(从磁盘上的文件读取,而不是动态生成,只是为了让我们知道生成代码不是问题):

file = open('C:\\test.pdf','rb') 
pdfFile = file.read() 
sys.stdout.write(pdfFile)

【问题讨论】:

  • 当你做sys.stdout.write() 什么没用?
  • 解释见上文,但问题基本上是python在尝试将二进制流转换为字符串以进行写入时添加回车。
  • sys.stdout = os.fdopen(1, "wb") 是否可以帮助您消除文本模式转换? (如果您不希望打印语句中的 NL,您仍然需要使用 sys.stdout.write。)(docs.python.org/library/os.html#os.fdopen
  • 感谢您提出的好问题。我今天学到了一些新东西。
  • @Roger,令人惊讶的是os.fdopen 并没有解决它,尽管使用-u 运行python 可以。 -u 确实带来了额外的开销

标签: python binary stdout


【解决方案1】:

你在哪个平台上?

如果你在 Windows 上,你可以试试this recipe(链接表明它是 Windows 特定的)。

if sys.platform == "win32":
    import os, msvcrt
    msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)

网络上有一些参考资料表明 Python 3.1 中将/应该有一个函数以二进制模式重新打开 sys.stdout,但我真的不知道是否有比上述 Python 2.x 更好的替代方案。

【讨论】:

  • 我做了一个测试,只是从文件中读取 PDF 并将其直接写回,仍然添加回车。
  • 您提供的windows解决方案链接是完美的解决方案。我感激不尽;这把我逼疯了。
  • 太棒了! stdin 同样适用,并且两者都需要制作例如可以处理二进制文件的功能性cat 克隆
【解决方案2】:

您可以使用无缓冲模式:python -u script.py

-u 强制标准输入、标准输出和标准错误完全无缓冲。 在重要的系统上,还要放置标准输入、标准输出和标准错误 在二进制模式。

【讨论】:

    【解决方案3】:

    您可以使用argopen.argopen(),它将破折号处理为标准输入/标准输出,并修复了Windows上的二进制模式。

    import argopen
    stdout = argopen.argopen('-', 'wb')
    stdout.write(some_binary_data)
    

    【讨论】:

    • 这比 ActiveState 配方要简洁得多。你是怎么想出来的?该模块几乎没有记录。
    • 对我不起作用——我的发行版没有 argopen。不想安装它,因为上面提到的“msvcrt.setmode()”对我有用。
    【解决方案4】:

    在 Python 2.x 中,所有字符串默认都是二进制字符数组,所以我相信你应该能够做到

    >>> sys.stdout.write(data)
    

    编辑:我已经确认了你的经验。

    我创建了一个文件,gen_bytes.py

    import sys
    for char in range(256):
        sys.stdout.write(chr(char))
    

    还有另一个 read_bytes.py

    import subprocess
    import sys
    
    proc = subprocess.Popen([sys.executable, 'gen_bytes.py'], stdout=subprocess.PIPE)
    res = proc.wait()
    bytes = proc.stdout.read()
    if not len(bytes) == 256:
        print 'Received incorrect number of bytes: {0}'.format(len(bytes))
        raise SystemExit(1)
    if not map(ord, bytes) == range(256):
        print 'Received incorrect bytes: {0}'.format(map(ord, bytes))
        raise SystemExit(2)
    print "Everything checks out"
    

    将它们放在同一目录中并运行 read_bytes.py。果然,看起来 Python 实际上是在输出换行符。我怀疑这只发生在 Windows 操作系统上。

    > .\read_bytes.py
    Received incorrect number of bytes: 257
    

    在 ChristopheD 的带领下,将 gen_bytes 更改为以下内容可以解决问题。

    import sys
    
    if sys.platform == "win32":
        import os, msvcrt
        msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    
    for char in range(256):
        sys.stdout.write(chr(char))
    

    为了完整起见,我将其包括在内。 ChristopheD 值得称赞。

    【讨论】:

    • 这适用于您只是尝试添加字符串数据,但 python 在调用 write 时会尝试对二进制数据进行字符串化,从而破坏数据。
    • 我在 Mac OS X 上运行了您的 gen_bytes.pyread_bytes.py(Python 2.5 对缺少的“格式”关键字进行了细微修改),并且它“一切都已检查”
    • 看起来这是一个仅限 Windows 的问题。
    • 在windows上,我发现只要运行gen_bytes.py > bytes.bin,只需执行dir就可以看到文件是257字节
    • 除非您使用的是 powershell,否则gen_bytes.py > bytes.bin 会生成一个 522 字节的 unicode 编码文件。
    【解决方案5】:

    我使用文件描述符的包装器解决了这个问题。 (在 Cygwin 上用 Python 3.2.5 测试)

    class BinaryFile(object):
        ''' Wraps a file-descriptor to binary read/write. The wrapped
        file can not be closed by an instance of this class, it must
        happen through the original file.
    
        :param fd: A file-descriptor (integer) or file-object that
            supports the ``fileno()`` method. '''
    
        def __init__(self, fd):
            super(BinaryFile, self).__init__()
            fp = None
            if not isinstance(fd, int):
                fp = fd
                fd = fp.fileno()
            self.fd = fd
            self.fp = fp
    
        def fileno(self):
            return self.fd
    
        def tell(self):
            if self.fp and hasattr(self.fp, 'tell'):
                return self.fp.tell()
            else:
                raise io.UnsupportedOperation(
                    'can not tell position from file-descriptor')
    
        def seek(self, pos, how=os.SEEK_SET):
            try:
                return os.lseek(self.fd, pos, how)
            except OSError as exc:
                raise io.UnsupportedOperation('file-descriptor is not seekable')
    
        def write(self, data):
            if not isinstance(data, bytes):
                raise TypeError('must be bytes, got %s' % type(data).__name__)
            return os.write(self.fd, data)
    
        def read(self, length=None):
            if length is not None:
                return os.read(self.fd, length)
            else:
                result = b''
                while True:
                    data = self.read(1024)
                    if not data:
                        break
                    result += data
                return result
    

    【讨论】:

    • 这个答案中的代码不能解决 Python 2.7 中的问题:\r 字节仍然出现在 Windows 的标准输出中。通过添加msvcrt.setmode(self.fd, os.O_BINARY)(如其他答案所示),\r 字节消失。
    猜你喜欢
    • 2010-12-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-04
    • 2010-10-28
    • 1970-01-01
    • 2012-10-13
    相关资源
    最近更新 更多