web-dev-qa-db-ja.com

Python 2.x-バイナリ出力をstdoutに書き込みますか?

Python 2.xでsys.stdoutにバイナリ出力を書き込む方法はありますか?Python 3.xでは、sys.stdoutを使用できます。バッファ(またはデタッチstdoutなど...)が、Python 2.5 /2.6の解決策を見つけることができませんでした。

編集、解決策:以下のChristopheDのリンクから:

import sys

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

編集:Webサーバーで提供するためにPDFファイル(バイナリ形式)をstdoutにプッシュしようとしています。sys.stdout.writeを使用してファイルを書き込もうとすると、 PDFが破損する原因となる、あらゆる種類のキャリッジリターンをバイナリストリームに追加します。

編集2:このプロジェクトでは、残念ながらWindows Serverで実行する必要があるため、Linuxソリューションはリリースされていません。

単純なダミーの例(オンザフライで生成するのではなく、ディスク上のファイルから読み取るため、生成コードが問題ではないことがわかります):

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

どのプラットフォームを使用していますか?

Windowsを使用している場合は、 このレシピ を試すことができます(リンクは、とにかくWindows固有であることを示しています)。

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

バイナリモードでsys.stdoutを再度開くためのPython 3.1)関数がある/はずであるといういくつかの参照がウェブ上にありますが、より良い代替手段があるかどうかは本当にわかりません。上記のPython 2.x。

29
ChristopheD

バッファなしモードを使用できます:python -u script.py

-ustdin、stdout、およびstderrを完全にバッファリング解除します。
重要なシステムでは、stdin、stdout、およびstderr 
もバイナリモードにします。
9
Tim Delaney

Python 2.xでは、すべての文字列はデフォルトでバイナリ文字配列であるため、次のことができるはずです。

>>> sys.stdout.write(data)

編集:私はあなたの経験を確認しました。

Gen_bytes.pyという1つのファイルを作成しました

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は実際には出力で改行を変換しているように見えます。これは、WindowsOSでのみ発生すると思われます。

> .\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は称賛に値します。

7
Jason R. Coombs

argopen 。argopen()を使用でき、ダッシュをstdin/stdoutとして処理し、Windowsのバイナリモードを修正します。

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

ファイル記述子のラッパーを使用してこれを解決しました。 (Python 3.2.5 on Cygwin)でテスト済み)

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
0
Niklas R