如何在Python中检查Windows操作系统上是否有数据可以从stdin读取?

8
这段代码。
select.select([sys.stdin], [], [], 1.0)

在Linux上,我想要的功能可以完美实现,但在Windows上却不行。

以前我曾经使用msvcrt中的kbhit()函数来检查stdin中是否有可读数据,但在这种情况下它总是返回0。此外,msvcrt.getch()返回'\xff',而sys.stdin.read(1)则返回'\x01'。看起来msvcrt函数的行为不正确。

不幸的是,我无法使用TCP套接字,因为我无法控制与我的Python程序通信的应用程序。

2个回答

2
在一些罕见的情况下,您可能关心stdin连接到了什么。大多数情况下,您并不需要关心 - 您只需读取stdin。
在“someprocess | python myprogram.py”中,stdin连接到管道;在这种情况下,先前进程的stdout。您只需从sys.stdin读取即可从另一个进程读取。[请注意,在Windows中,仍然有(可能)带有键盘的“CON”设备。它只是不会是sys.stdin。]
在“python myprogram.py
在“python myprogram.py”中,stdin保留在控制台上(在*nix中为/dev/ttyxx)。您只需从sys.stdin读取即可从键盘读取。
请注意以上三种情况中的共同主题。您只需从sys.stdin读取即可由程序环境为您定义一切。您不会检查“是否可以在stdin上读取数据”。它已经可用。
有时,您需要键盘中断(或其他恶作剧)。顺便说一句,Python将键盘中断作为I/O元素的第一类功能。在I/O期间,Control-C引发中断(它不会打破紧密循环,但会向定期打印的程序发出信号)。
有时您需要找出stdin连接的文件类型。
例如os.isatty(sys.stdin.fileno())。如果sys.stdin是TTY,则您的程序仍连接到Windows“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上是否有可读数据”。如果您能提供更多信息说明您想实现什么,这可能会有所帮助。

os.isatty(sys.stdin.fileno()) 返回 False。 - awatts

1

我运行一个线程从标准输入读取数据,然后将其转发到套接字。套接字是可选择的,因此标准输入也是可选择的。

在最近的项目中,我必须不断地从一个网络套接字读取数据,然后将其转发到另一个套接字,直到用户从控制台输入q为止。有人可能会想使用线程,但我不想处理多线程的问题。最后,我找到了一种不太清晰的解决方案,而且它起作用了。

我创建了一个线程 - 是的,线程,但没有多线程的问题 - 这个线程打开一个监听随机端口的服务器套接字,然后打开一个连接到该服务器的客户端套接字。服务器套接字接受连接,然后以阻塞方式调用 sys.stdin.read(),所有从标准输入中读取的数据都将写入已接受的连接中。因此,客户端套接字接收从标准输入读取的数据。现在,客户端套接字是可选择的标准输入,并且它是线程安全的。

源代码:

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

1
嗨,@Harvey感谢您的编辑,源代码在这里http://www.ideawu.com/blog/wp-content/uploads/2010/08/stdio.py_.zip - ideawu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接