2008-11-27 17 views
6

Este código¿Cómo saber si hay datos para leer desde stdin en Windows en Python?

select.select([sys.stdin], [], [], 1.0) 

hace exactamente lo que quiero en Linux, pero no en Windows.

He usado kbhit() en msvcrt antes para ver si los datos están disponibles en stdin para leer, pero en este caso siempre devuelve 0. Además, msvcrt.getch() devuelve '\xff', mientras que sys.stdin.read(1) devuelve '\x01'. Parece que las funciones msvcrt no se comportan correctamente.

Lamentablemente no puedo usar sockets TCP ya que no tengo el control de la aplicación hablando de mi programa Python.

Respuesta

2

En algunas situaciones excepcionales, es posible que le importe a qué stdin esté conectado. En general, no te importa, acabas de leer stdin.

En someprocess | python myprogram.py, stdin está conectado a una tubería; en este caso, el stdout del proceso anterior. Simplemente lea desde sys.stdin y está leyendo desde el otro proceso. [Tenga en cuenta que en Windows, sin embargo, todavía hay (potencialmente) un dispositivo "CON" con un teclado. Simplemente no será sys.stdin.]

En python myprogram.py <someFile, stdin está conectado a un archivo. Simplemente lea desde sys.stdin y está leyendo desde el archivo.

En python myprogram.py, stdin queda conectado a la consola (/dev/ttyxx en * nix). Usted simple lectura de sys.stdin y está leyendo desde el teclado.

Tenga en cuenta el tema común en los tres casos anteriores. Simplemente lea desde sys.stdin y el entorno de su programa lo define todo por usted. No verifica "para ver si los datos están disponibles en stdin para leer". Ya está disponible.

A veces, desea una interrupción del teclado (u otras travesuras). Python, BTW, tiene una interrupción de teclado como característica de primera clase de los elementos de E/S. Control-C genera una interrupción durante la E/S (no se romperá en un circuito cerrado, pero indicará un programa que imprime periódicamente.)

A veces necesita averiguar a qué tipo de archivo está conectado el archivo stdin .

Algo así como os.isatty(sys.stdin.fileno()) Si sys.stdin es un TTY, su programa fue dejado conectado a la ventana "CON" (el teclado). Si sys.stdin no es un TTY, está conectado a un archivo o una tubería.


Ejemplo

Microsoft Windows XP [Version 5.1.2600] 
(C) Copyright 1985-2001 Microsoft Corp. 

C:\Documents and Settings\slott>python 
Python 2.5.2 (r252:60911, Feb 21 2008, 13:11:45) [MSC v.1310 32 bit (Intel)] on 
win32 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import os 
>>> import sys 
>>> os.isatty(sys.stdin.fileno()) 
True 
>>> 

El valor de True me dice Python se está ejecutando sin un archivo o una tubería conectada. sys.stdin es el teclado. Usar Windows kbhit es innecesario.

Un valor de False me dice que Python se está ejecutando con un archivo o un conducto adjunto. sys.stdin NO es el teclado. Verificar kbhit puede ser significativo.Además, podría abrir el dispositivo CON: y leer el teclado directamente, separado de sys.stdin.


no estoy seguro de por qué es necesario "para ver si hay datos disponibles sobre la entrada estándar para la lectura". Puede ser útil actualizar tu pregunta con detalles adicionales de lo que intentas lograr.

+0

os.isatty (sys.stdin.fileno()) devuelve Falso – awatts

1

Ejecuto un hilo que lee de stdin, luego reenvío los datos a un socket. El zócalo es seleccionable, por lo tanto, stdin también se puede seleccionar.

En un proyecto reciente, debo leer continuamente desde un socket de red, reenviar a otro socket, hasta que el usuario ingrese q desde la consola. Uno puede pensar en usar el enhebrado, pero no quiero ocuparme de productos de múltiples hilos. Finalmente, encontré una solución no clara, y funcionó.

Creo un hilo - SÍ, hilo, pero no hay preocupaciones de hilos múltiples - este hilo abre un socket de servidor que escucha en un puerto aleatorio, luego abre un socket de cliente conéctate a este servidor. El socket del servidor acepta la conexión y luego llama al sys.stdin.read() de forma bloqueada, todos los datos leídos desde stdin escribirán en esa conexión aceptada. Entonces, el socket del cliente recibe la lectura de datos de stdin. Ahora, el socket del cliente es seleccionable stdin, y es seguro para subprocesos. código

Fuente:

# coding=UTF-8 
""" === Windows stdio === 
@author [email protected] 
@link http://www.ideawu.net/ 
File objects on Windows are not acceptable for select(), 
this module creates two sockets: stdio.s_in and stdio.s_out, 
as pseudo stdin and stdout. 

@example 
from stdio import stdio 
stdio.write('hello world') 
data = stdio.read() 
print stdio.STDIN_FILENO 
print stdio.STDOUT_FILENO 
""" 
import thread 
import sys, os 
import socket 

# socket read/write in multiple threads may cause unexpected behaviors 
# so use two separated sockets for stdin and stdout 

def __sock_stdio(): 
    def stdin_thread(sock, console): 
     """ read data from stdin, and write the data to sock 
     """ 
     try: 
      fd = sys.stdin.fileno() 
      while True: 
       # DO NOT use sys.stdin.read(), it is buffered 
       data = os.read(fd, 1024) 
       #print 'stdin read: ' + repr(data) 
       if not data: 
        break 
       while True: 
        nleft = len(data) 
        nleft -= sock.send(data) 
        if nleft == 0: 
         break 
     except: 
      pass 
     #print 'stdin_thread exit' 
     sock.close() 

    def stdout_thread(sock, console): 
     """ read data from sock, and write to stdout 
     """ 
     try: 
      fd = sys.stdout.fileno() 
      while True: 
       data = sock.recv(1024) 
       #print 'stdio_sock recv: ' + repr(data) 
       if not data: 
        break 
       while True: 
        nleft = len(data) 
        nleft -= os.write(fd, data) 
        if nleft == 0: 
         break 
     except: 
      pass 
     #print 'stdin_thread exit' 
     sock.close() 


    class Console: 
     def __init__(self): 
      self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
      self.serv.bind(('127.0.0.1', 0)) 
      self.serv.listen(5) 
      port = self.serv.getsockname()[1] 

      # data read from stdin will write to this socket 
      self.stdin_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
      self.stdin_sock.connect(('127.0.0.1', port)) 
      self.s_in, addr = self.serv.accept() 
      self.STDIN_FILENO = self.s_in.fileno() 
      thread.start_new_thread(stdin_thread, (self.stdin_sock, self)) 

      # data read from this socket will write to stdout 
      #self.stdout_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
      #self.stdout_sock.connect(('127.0.0.1', port)) 
      #self.s_out, addr = self.serv.accept() 
      #self.STDOUT_FILENO = self.s_out.fileno() 
      #thread.start_new_thread(stdout_thread, (self.stdout_sock, self)) 

      self.read_str = '' # read buffer for readline 

     def close(self): 
      self.s_in.close() 
      self.s_out.close() 
      self.stdin_sock.close() 
      self.stdout_sock.close() 
      self.serv.close() 

     def write(self, data): 
      try: 
       return self.s_out.send(data) 
      except: 
       return -1 

     def read(self): 
      try: 
       data = self.s_in.recv(4096) 
      except: 
       return '' 
      ret = self.read_str + data 
      self.read_str = '' 
      return ret 

     def readline(self): 
      while True: 
       try: 
        data = self.s_in.recv(4096) 
       except: 
        return '' 
       if not data: 
        return '' 
       pos = data.find('\n') 
       if pos == -1: 
        self.read_str += data 
       else: 
        left = data[0 : pos + 1] 
        right = data[pos + 1 : ] 
        ret = self.read_str + left 
        self.read_str = right 
        return ret 

    stdio = Console() 
    return stdio 

def __os_stdio(): 
    class Console: 
     def __init__(self): 
      self.STDIN_FILENO = sys.stdin.fileno() 
      self.STDOUT_FILENO = sys.stdout.fileno() 

     def close(self): 
      pass 

     def write(self, data): 
      try: 
       return os.write(self.STDOUT_FILENO, data) 
      except: 
       return -1 

     def read(self): 
      try: 
       return os.read(self.STDIN_FILENO, 4096) 
      except: 
       return '' 

     def readline(self): 
      try: 
       return sys.stdin.readline() 
      except: 
       return '' 

    stdio = Console() 
    return stdio 

if os.name == 'posix': 
    stdio = __os_stdio() 
else: 
    stdio = __sock_stdio() 
+1

Hola, gracias por @Harvey editado, el código fuente aquí http: //www.ideawu .com/blog/wp-content/uploads/2010/08/stdio.py_.zip – ideawu

Cuestiones relacionadas