Python 2.x – ¿Escribir salida binaria en stdout?

¿Hay alguna forma de escribir una salida binaria en sys.stdout en Python 2.x? En Python 3.x, puedes usar sys.stdout.buffer (o separar stdout, etc.), pero no he podido encontrar ninguna solución para Python 2.5 / 2.6.

EDITAR, Solución : Desde el enlace de ChristopheD, a continuación:

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

EDITAR: Estoy intentando enviar un archivo PDF (en formato binario) a la salida estándar para servir en un servidor web. Cuando bash escribir el archivo utilizando sys.stdout.write, agrega todo tipo de retornos de carro a la secuencia binaria que hace que el PDF se vuelva corrupto.

EDIT 2: para este proyecto, necesito ejecutarlo en un servidor Windows, desafortunadamente, así que las soluciones de Linux están fuera.

Ejemplo simplemente ficticio (leer un archivo en el disco, en lugar de generar sobre la marcha, solo para que sepamos que el código de generación no es el problema):

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

¿En que plataforma Estas tu?

Puedes probar esta receta si estás en Windows (el enlace sugiere que es específico de Windows de todos modos).

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

Hay algunas referencias en la web de que habría / debería haber una función en Python 3.1 para volver a abrir sys.stdout en modo binario, pero realmente no sé si hay una mejor alternativa que la anterior para Python 2.x.

Puede utilizar el modo sin almacenamiento en búfer: python -u script.py .

 -u Fuerza a stdin, stdout y stderr a estar totalmente sin búfer.
        En sistemas donde importa, también ponga stdin, stdout y stderr
        en modo binario.

En Python 2.x, todas las cadenas son arrays de caracteres binarios por defecto, así que creo que deberías poder simplemente

 >>> sys.stdout.write(data) 

EDIT: He confirmado su experiencia.

He creado un archivo, gen_bytes.py

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

Y otro 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" 

Póngalos en el mismo directorio y ejecute read_bytes.py. Efectivamente, parece que Python está de hecho convirtiendo nuevas líneas en la salida. Sospecho que esto solo sucede en un sistema operativo Windows.

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

Seguir el ejemplo de ChristopheD y cambiar gen_bytes a lo siguiente corrige el problema.

 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)) 

Incluyo esto para completar. ChristopheD merece el crédito.

Puede usar argopen .argopen (), maneja el guión como stdin / stdout, y corrige el modo binario en Windows.

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

Resolví esto usando un contenedor para un descriptor de archivo. (Probado en Python 3.2.5 en 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