2010-03-03 15 views
31

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

EDITAR, Solución: De enlace de ChristopheD, a continuación:

import sys 

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

EDIT: Estoy tratando de empujar un archivo PDF (en forma binaria) a la salida estándar para servir en un servidor web. Cuando intento escribir el archivo usando 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, tengo que ejecutar en un servidor de Windows, desafortunadamente, para que las soluciones Linux estén fuera.

Simplemente maniquí Ejemplo (lectura de un archivo en el disco, en lugar de generar sobre la marcha, por lo que sólo saben que el código de generación no es la cuestión):

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

Cuando hiciste 'sys.stdout.write()' ¿qué no funcionó? –

+0

Consulte la explicación anterior, pero el problema es básicamente que python agrega retornos de carro cuando intenta convertir la secuencia binaria en una cadena para escritura. – Eavesdown

+0

¿'sys.stdout = os.fdopen (1," wb ")' funciona para que usted elimine las conversiones de modo de texto? (Todavía necesitará usar sys.stdout.write si no desea que las NL se impriman). (Http://docs.python.org/library/os.html#os.fdopen) –

Respuesta

24

¿En qué plataforma estás?

Puede probar this recipe si está 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 que no habría/debería ser una función en Python 3.1 para reabrir sys.stdout en modo binario, pero no se sabe muy bien si hay una mejor alternativa a continuación, lo anterior para Python 2. X.

+0

Hice una prueba solo leyendo el PDF desde un archivo y escribiéndolo directamente de vuelta, los retornos de carro aún se agregan. – Eavesdown

+0

El enlace de la solución de Windows que ofrece es la solución perfecta. No puedo agradecerte lo suficiente; esto me estaba conduciendo a la pared. – Eavesdown

+0

+1 ¡Gracias por esto! – Sabuncu

6

En Python 2.x, todas las cadenas de caracteres binarios son matrices de forma predeterminada, por lo que creo que debe ser capaz de 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 otra 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" 

ponerlos en el mismo directorio y ejecutar read_bytes.py. Efectivamente, parece como si Python estuviera convirtiendo líneas nuevas en la salida. Sospecho que esto solo ocurre en un sistema operativo Windows.

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

Siguiendo el ejemplo de ChristopheD, y el cambio de gen_bytes a la 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)) 

Lo incluyo para que esté completo. ChristopheD merece el crédito.

+0

Esto funciona si solo está tratando de agregar datos de cadena, pero Python intenta codificar datos binarios al llamar a escritura, corrompiendo los datos. – Eavesdown

+0

Ejecuté su 'gen_bytes.py' y' read_bytes.py' en Mac OS X (Python 2.5 con modificaciones menores para las palabras clave de "formato" faltantes) y "Todo borrado" –

+0

Parece que es un problema solo de Windows . – Eavesdown

5

Puede usar argopen .argopen(), maneja dash como stdin/stdout, y arregla el modo binario en Windows.

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

Esto es mucho más nítido que la receta ActiveState. ¿Cómo lo descubriste? El módulo está apenas documentado. –

+0

No funcionó para mí, mi distribución no tiene argopen. No quería instalarlo ya que "msvcrt.setmode()" mencionado anteriormente funcionó para mí. –

7

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

 
-u  Force stdin, stdout and stderr to be totally unbuffered. 
     On systems where it matters, also put stdin, stdout and stderr 
     in binary mode. 
0

Lo resolví 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 
Cuestiones relacionadas