Как узнать, есть ли данные для чтения из stdin на Windows в Python? - PullRequest
6 голосов
/ 27 ноября 2008

Этот код

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

делает именно то, что я хочу в Linux, но не в Windows.

Я использовал kbhit() в msvcrt прежде, чтобы посмотреть, доступны ли данные на stdin для чтения, но в этом случае он всегда возвращает 0. Кроме того, msvcrt.getch() возвращает '\xff', тогда как sys.stdin.read(1) возвращает '\x01'. Кажется, что функции msvcrt не работают должным образом.

К сожалению, я не могу использовать TCP-сокеты, так как я не контролирую приложение, говорящее о моей программе на Python.

Ответы [ 2 ]

2 голосов
/ 27 ноября 2008

В некоторых редких случаях вам может быть важно, к чему подключен stdin. В основном, тебе все равно - ты просто читаешь stdin.

В someprocess | python myprogram.py стандартный ввод подключен к трубе; в этом случае стандартный вывод предыдущего процесса. Вы просто читаете из sys.stdin, а вы читаете из другого процесса. [Обратите внимание, что в Windows все еще есть (потенциально) устройство «CON» с клавиатурой. Это просто не будет sys.stdin.]

В python myprogram.py <someFile stdin подключен к файлу. Вы просто читаете из sys.stdin и читаете из файла.

В python myprogram.py стандартный вывод остается подключенным к консоли (/dev/ttyxx в * nix). Вы просто читаете с sys.stdin и читаете с клавиатуры.

Обратите внимание на общую тему в вышеупомянутых трех случаях. Вы просто читаете из sys.stdin, и среда вашей программы определяет все для вас. Вы не проверяете «чтобы увидеть, доступны ли данные на stdin для чтения». Это уже доступно.

Иногда требуется прерывание клавиатуры (или другие махинации). В Python, кстати, прерывание клавиатуры является первоклассной функцией элементов ввода / вывода. Control-C вызывает прерывание во время ввода-вывода (оно не прерывается в узком цикле, но будет сигнализировать программе, которая печатает периодически.)

Иногда вам нужно выяснить, к какому файлу stdin подключен.

Что-то вроде os.isatty( sys.stdin.fileno() ) Если sys.stdin - это TTY, ваша программа осталась подключенной к окнам "CON" (клавиатура). Если sys.stdin не TTY, он подключен к файлу или каналу.


Пример * * одна тысяча тридцать одна

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

Значение True говорит мне, что Python работает без прикрепленного файла или канала. sys.stdin это клавиатура. Использование windows kbhit не нужно.

Значение False говорит мне, что Python работает с прикрепленным файлом или каналом. sys.stdin это НЕ клавиатура. Проверка kbhit может иметь смысл. Кроме того, я мог бы открыть устройство CON: и сразу прочитать клавиатуру, отдельно от sys.stdin.


Я не уверен, почему вам нужно "посмотреть, доступны ли данные на stdin для чтения". Это может помочь обновить ваш вопрос дополнительными сведениями о том, что вы пытаетесь выполнить.

1 голос
/ 22 августа 2010

Я запускаю поток, который читает из stdin, затем перенаправляет данные в сокет. Можно выбрать сокет, поэтому можно выбрать и стандартный ввод.

В недавнем проекте я должен постоянно читать из одного сетевого сокета, пересылать в другой сокет, пока пользователь не введет q с консоли. Можно подумать об использовании многопоточности, но я не хочу иметь дело с многопоточными вещами. Наконец, я нашел неясное решение, и оно сработало.

Я создаю один поток - ДА, поток, но без проблем с несколькими потоками - этот поток открывает сокет сервера, прослушивающий произвольный порт, а затем открывает клиентский сокет, подключенный к этому серверу. Сокет сервера принимает соединение, затем вызывает sys.stdin.read() блокированным способом, все данные, считанные из stdin, будут записаны в это принятое соединение. Таким образом, клиентский сокет получает данные из стандартного ввода. Теперь клиентский сокет является выбираемым стандартным и является поточно-ориентированным.

Исходный код:

# coding=UTF-8
""" === Windows stdio ===
@author ideawu@163.com
@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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...