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)
どのプラットフォームを使用していますか?
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。
バッファなしモードを使用できます:python -u script.py
。
-ustdin、stdout、およびstderrを完全にバッファリング解除します。 重要なシステムでは、stdin、stdout、およびstderr もバイナリモードにします。
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は称賛に値します。
argopen 。argopen()を使用でき、ダッシュをstdin/stdoutとして処理し、Windowsのバイナリモードを修正します。
import argopen
stdout = argopen.argopen('-', 'wb')
stdout.write(some_binary_data)
ファイル記述子のラッパーを使用してこれを解決しました。 (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