2010-05-17 8 views
21

Est-il possible de lire stdin en tant que données binaires dans Python 2.6? Si c'est le cas, comment?Lecture de données binaires à partir de stdin

Je vois dans le Python 3.1 documentation que c'est assez simple, mais les facilités pour faire cela dans 2.6 ne semblent pas être là.

Si les méthodes décrites en 3.1 ne sont pas disponibles, existe-t-il un moyen de fermer stdin et rouvrir en mode binaire?

Mise à jour

Pour être clair, je me sers de « type » dans une coquille MS-DOS pour tuyau le contenu d'un fichier binaire à mon code python. Cela devrait être l'équivalent d'une commande "chat" Unix, autant que je comprends. Mais quand je teste cela, je reçois toujours un octet de moins que la taille de fichier attendue.

Mise à jour # 2

Tout d'abord, merci pour toutes les réponses. Je travaille lentement vers une solution réelle et utilisable ici. À la fin, j'essaie toujours de construire un fichier JAR autonome qui exécute mon code Python en passant automatiquement par tous les arguments de la ligne de commande sans tache.

La raison pour laquelle je vais sur la route Java/JAR/Jython est que l'une de mes bibliothèques externes principales est seulement disponible en Java JAR. Mais malheureusement, j'avais commencé mon travail en tant que Python. Il aurait peut-être été plus facile de convertir mon code à Java il y a quelque temps, mais comme tout cela était supposé être compatible, j'ai pensé que j'essaierais de le faire passer en revue et de prouver que cela pouvait être fait.

Dans le cas où quelqu'un se demandait, c'est aussi lié à la question que j'ai posée il y a quelques jours.

Packaging and deploying a Jython program from Eclipse

Une partie de cette question a été répondu à cette question.

Donc, je vais essayer de mettre à jour ma question originale avec quelques notes sur ce que j'ai compris jusqu'à présent.

Répondre

13

Utilisez le -u command line switch pour forcer Python 2 à traiter stdin, stdout et stderr en tant que flux binaires sans tampon.

C:> type mydoc.txt | python.exe -u myscript.py 
+0

J'ai testé cela avec 'type' et il semble fonctionner. C'est-à-dire, si je laisse de côté le drapeau -u, j'obtiens un caractère de moins par ligne. –

+0

Cool. Merci pour le test. Donc, juste parce que je vous aime tellement, aucune idée comment passer l'option '-u' à travers la classe JarRunner.java qui est utilisée pour déclencher Jython à travers un fichier JAR exécutable? Je sais. Je ne fais jamais rien de la manière la plus simple. – thebeav

+1

Selon docs, la définition de la variable d'environnement PYTHONUNBUFFERED aura le même effet. Je ne sais pas si cela aide. –

-2
import sys 

data = sys.stdin.read(10) # Read 10 bytes from stdin 

Si vous avez besoin d'interpréter les données binaires, utilisez le module struct.

+0

Si je l'appelle alors sys.stdin.read() sans paramètre, il devrait lire toutes les données binaires qui ont été fournies, correct? Comment puis-je déterminer la longueur correctement? len (data) renvoie la valeur incorrecte si le dernier octet de la donnée était un zéro. Comment vérifiez-vous et corrigez-vous cette situation? – thebeav

+1

'len' compte les caractères \ x00 dans la chaîne. Python n'a pas de chaînes terminées par un caractère nul. 'len (" Hello \ x00 ") == 6' –

+0

Je me demande alors si ce pourrait être la commande 'type' du shell MS-DOS qui cause la perte de l'octet final? Je suppose que je vais devoir tester l'équivalent sur Linux. Merci. – thebeav

9

Si vous avez besoin ... ce Ce test simple que je l'ai utilisé pour lire le fichier binaire qui contient le caractère 0x1A dans entre

import os, sys, msvcrt 

msvcrt.setmode (sys.stdin.fileno(), os.O_BINARY) 
s = sys.stdin.read() 
print len (s) 

Mes données du fichier de test a été:

0x23, 0x1A, 0x45 

Sans définir le mode binaire en mode binaire, ce test imprime 1 dès qu'il traite 0x1A comme EOF. Bien sûr, cela ne fonctionne que sur les fenêtres, car cela dépend du module msvcrt.

+1

Mais Windows est le seul système où la plupart des gens vont rencontrer un problème, donc cela devrait être une solution acceptable. –

+1

C'est la solution correcte pour Python 2 pour récupérer les octets bruts de stdin sur Windows. Sur Unix, il n'y a pas de différence entre le mode binaire et le mode normal. Voir ce sujet: http://code.activestate.com/lists/python-list/20426/ (rouvrir stdin en mode brut (binaire)?) –

+0

Voir aussi http://cygwin.com/cygwin-ug- net/using-textbinary.html –

17

A partir de la documentation (voir here):

The standard streams are in text mode by default. To write or read binary data to these, use the underlying binary buffer. For example, to write bytes to stdout, use sys.stdout.buffer.write(b'abc') .

Mais, comme dans la réponse acceptée, en invoquant python avec une -u est une autre option qui force stdin, stdout et stderr être totalement unbuffered. Voir la page de manuel python (1) pour plus de détails. Voir le documentation on io pour plus d'informations sur la mise en mémoire tampon de texte et utiliser sys.stdin.detach() pour désactiver la mise en mémoire tampon à partir de Python.

+6

que doc conduit à docs py3k, pas ce que le PO veut traiter. –

+1

J'ai essayé '-u' avec Python v3.2.5 mais cela n'a rien fait d'utile. Mais utiliser 'sys.stdout.buffer' fonctionne plutôt bien sur Python 2.7.8 il n'y a pas de telle fonctionnalité. – ony

+0

La question de l'OP portait sur Python 2.6. – Yuval

13

Voici la coupe finale pour Linux/Windows Python 2/3 de code compatible pour lire les données stdin sans corruption:

import sys 

PY3K = sys.version_info >= (3, 0) 

if PY3K: 
    source = sys.stdin.buffer 
else: 
    # Python 2 on Windows opens sys.stdin in text mode, and 
    # binary data that read from it becomes corrupted on \r\n 
    if sys.platform == "win32": 
     # set sys.stdin to binary mode 
     import os, msvcrt 
     msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) 
    source = sys.stdin 

b = source.read() 
Questions connexes