This code
select.select([sys.stdin], [], [], 1.0)
does exactly what I want on Linux, but not in Windows.
I've used kbhit()
in msvcrt
before to see if data is available on stdin for reading, but in this case it always returns 0
. Additionally msvcrt.getch()
returns '\xff'
whereas sys.stdin.read(1)
returns '\x01'
. It seems as if the msvcrt functions are not behaving properly.
Unfortunately I can't use TCP sockets as I'm not in control of the application talking my Python program.
In some rare situations, you might care what stdin is connected to. Mostly, you don't care -- you just read stdin.
In someprocess | python myprogram.py
, stdin is connected to a pipe; in this case, the stdout of the previous process. You simply read from sys.stdin
and you're reading from the other process. [Note that in Windows, however, there's still (potentially) a "CON" device with a keyboard. It just won't be sys.stdin
.]
In python myprogram.py <someFile
, stdin is connected to a file. You simply read from sys.stdin
and you're reading from the file.
In python myprogram.py
, stdin is left connected to the console (/dev/ttyxx
in *nix). You simple read from sys.stdin
and you're reading from the keyboard.
Note the common theme in the above three cases. You simply read from sys.stdin
and your program's environment defines everything for you. You don't check "to see if data is available on stdin for reading". It's already available.
Sometimes, you want a keyboard interrupt (or other shenanigans). Python, BTW, has a keyboard interrupt as a first-class feature of the I/O elements. Control-C raises an interrupt during I/O (it won't break into a tight loop, but it will signal a program that prints periodically.)
Sometimes you need to find out what kind of file stdin
is connected to.
Something like os.isatty( sys.stdin.fileno() )
If sys.stdin
is a TTY, you're program was left connected to the windows "CON" (the keyboard). If sys.stdin
is not a TTY, it's connected to a file or a pipe.
Example
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
>>>
The value of True
tells me Python is running without a file or pipe attached. sys.stdin
is the keyboard. Using windows kbhit
is needless.
A value of False
tells me Python is running with a file or pipe attached. sys.stdin
is NOT the keyboard. Checking kbhit
might be meaningful. Also, I could open the CON:
device and read the keyboard directly, separate from sys.stdin
.
I'm not sure why you need "to see if data is available on stdin for reading". It might help to update your question with additional details of what you're trying to accomplish.
I run a thread that reads from stdin, then forward the data to a socket. The socket is selectable, so, stdin is selectable too.
In a recent project, I must continuously read from one network socket, forward to another socket, until the user inputs
q
from the console. One may think to use threading, but I don’t want to deal with multi-thread stuffs. Finally, I found a none-clear solution, and it worked.I create one thread – YES, thread, but no multi-thread concerns – this thread open a server socket listening on random port, then open a client socket connect to this server. The server socket accept the connection, then call
sys.stdin.read()
in a block way, all data read from stdin will write to that accepted connection. So client socket receive data reading from stdin. Now, the client socket is a selectable stdin, and it is thread-safe.
Source code:
# 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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With