[英]When working with a named pipe is there a way to do something like readlines()
Overall Goal: I am trying to read some progress data from a python exe to update the progress of the exe in another application 总体目标:我正在尝试从python exe读取一些进度数据,以在另一个应用程序中更新exe的进度
I have a python exe that is going to do some stuff, I want to be able to communicate the progress to another program. 我有一个要执行某些操作的python exe,我希望能够将进度传达给另一个程序。 Based on several other Q&A here I have been able to have my running application send progress data to a named pipe using the following code
基于这里的其他一些问答,我能够使用以下代码使正在运行的应用程序将进度数据发送到命名管道
import win32pipe
import win32file
import glob
test_files = glob.glob('J:\\someDirectory\\*.htm')
# test_files has two items a.htm and b.htm
p = win32pipe.CreateNamedPipe(r'\\.\pipe\wfsr_pipe',
win32pipe.PIPE_ACCESS_DUPLEX,
win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT,
1,65536,65536,300,None)
# the following line is the server-side function for accepting a connection
# see the following SO question and answer
""" http://stackoverflow.com/questions/1749001/named-pipes-between-c-sharp-and-python
"""
win32pipe.ConnectNamedPipe(p, None)
for each in testFiles:
win32file.WriteFile(p,each + '\n')
#send final message
win32file.WriteFile(p,'Process Complete')
# close the connection
p.close()
In short the example code writes the path of the each file that was globbed to the NamedPipe - this is useful and can be easily extended to more logging type events. 简而言之,示例代码将每个文件的路径写入到NamedPipe中-这很有用,并且可以轻松地扩展到更多日志类型事件。 However, the problem is trying to figure out how to read the content of the named pipe without knowing the size of each possible message.
但是,问题是试图弄清楚如何在不知道每个可能的消息大小的情况下读取命名管道的内容。 For example the first file could be named J:\\someDirectory\\a.htm, but the second could have 300 characters in the name.
例如,第一个文件可以命名为J:\\ someDirectory \\ a.htm,但是第二个文件可以包含300个字符。
So far the code I am using to read the contents of the pipe requires that I specify a buffer size 到目前为止,我用于读取管道内容的代码要求我指定缓冲区大小
First establish the connection 首先建立连接
file_handle = win32file.CreateFile("\\\\.\\pipe\\wfsr_pipe",
win32file.GENERIC_READ | win32file.GENERIC_WRITE,
0, None,
win32file.OPEN_EXISTING,
0, None)
and then I have been playing around with reading from the file 然后我一直在玩读文件
data = win32file.ReadFile(file_handle,128)
This generally works but I really want to read until I hit a newline character, do something with the content between when I started reading and the newline character and then repeat the process until I get to a line that has Process Complete in the line 通常这是可行的,但我真的很想读,直到我碰到换行符为止,在我开始阅读和换行符之间进行内容处理,然后重复该过程,直到行中出现Process Complete为止。
I have been struggling with how to read only until I find a newline character (\\n). 在寻找换行符(\\ n)之前,我一直在努力只阅读。 I basically want to read the file by lines and based on the content of the line do something (either display the line or shift the application focus).
我基本上想按行读取文件,并根据行的内容执行某些操作(显示行或转移应用程序焦点)。
Based on the suggestion provided by @meuh I am updating this because I think there is a dearth of examples, guidance in how to use pipes 根据@meuh提供的建议,我正在对此进行更新,因为我认为缺少示例,如何使用管道的指南
My server code 我的服务器代码
import win32pipe
import win32file
import glob
import os
p = win32pipe.CreateNamedPipe(r'\\.\pipe\wfsr_pipe',
win32pipe.PIPE_ACCESS_DUPLEX,
win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT,
1,65536,65536,300,None)
# the following line is the server-side function for accepting a connection
# see the following SO question and answer
""" http://stackoverflow.com/questions/1749001/named-pipes-between-c-sharp-and-python
"""
win32pipe.ConnectNamedPipe(p, None)
for file_id in glob.glob('J:\\level1\\level2\\level3\\*'):
for filer_id in glob.glob(file_id + os.sep + '*'):
win32file.WriteFile(p,filer_id)
#send final message
win32file.WriteFile(p,'Process Complete')
# close the connection
p.close() #still not sure if this should be here, I need more testing
# I think the client can close p
The Client code 客户端代码
import win32pipe
import win32file
file_handle = win32file.CreateFile("\\\\.\\pipe\\wfsr_pipe",
win32file.GENERIC_READ |
win32file.GENERIC_WRITE,
0, None,win32file.OPEN_EXISTING,0, None)
# this is the key, setting readmode to MESSAGE
win32pipe.SetNamedPipeHandleState(file_handle,
win32pipe.PIPE_READMODE_MESSAGE, None, None)
# for testing purposes I am just going to write the messages to a file
out_ref = open('e:\\testpipe.txt','w')
dstring = '' # need some way to know that the messages are complete
while dstring != 'Process Complete':
# setting the blocksize at 4096 to make sure it can handle any message I
# might anticipate
data = win32file.ReadFile(file_handle,4096)
# data is a tuple, the first position seems to always be 0 but need to find
# the docs to help understand what determines the value, the second is the
# message
dstring = data[1]
out_ref.write(dstring + '\n')
out_ref.close() # got here so close my testfile
file_handle.close() # close the file_handle
I don't have windows but looking through the api it seems you should convert your client to message mode by adding after the CreateFile() the call: 我没有Windows,但是通过api看来,您应该通过在CreateFile()之后添加调用来将客户端转换为消息模式:
win32pipe.SetNamedPipeHandleState(file_handle,
win32pipe.PIPE_READMODE_MESSAGE, None, None)
then each sufficiently long read will return a single message, ie what the other wrote in a single write. 那么每次足够长的读取将返回一条消息,即另一条消息在一次写入中所写的内容。 You already set PIPE_TYPE_MESSAGE when you created the pipe.
创建管道时,您已经设置了PIPE_TYPE_MESSAGE。
You could simply use an implementation of io.IOBase that would wrap the NamedPipe. 您可以简单地使用io.IOBase的实现来包装NamedPipe。
class PipeIO(io.RawIOBase):
def __init__(self, handle):
self.handle = handle
def read(self, n):
if (n == 0): return ""
elif n == -1: return self.readall()
data = win32file.ReadFile(self.file_handle,n)
return data
def readinto(self, b):
data = self.read(len(b))
for i in range(len(data)):
b[i] = data[i]
return len(data)
def readall(self):
data = ""
while True:
chunk = win32file.ReadFile(self.file_handle,10240)
if (len(chunk) == 0): return data
data += chunk
BEWARE : untested, but it should work after fixing the eventual typos. 注意:未经测试,但在修正最终的错字后应该可以使用。
You could then do: 然后,您可以执行以下操作:
with PipeIO(file_handle) as fd:
for line in fd:
# process a line
You could use the msvcrt
module and open
to turn the pipe into a file object. 您可以使用
msvcrt
模块并open
以将管道变成文件对象。
import win32pipe
import os
import msvcrt
from io import open
pipe = win32pipe.CreateNamedPipe(r'\\.\pipe\wfsr_pipe',
win32pipe.PIPE_ACCESS_OUTBOUND,
win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT,
1,65536,65536,300,None)
# wait for another process to connect
win32pipe.ConnectNamedPipe(pipe, None)
# get a file descriptor to write to
write_fd = msvcrt.open_osfhandle(pipe, os.O_WRONLY)
with open(write_fd, "w") as writer:
# now we have a file object that we can write to in a standard way
for i in range(0, 10):
# create "a\n" in the first iteration, "bb\n" in the second and so on
text = chr(ord("a") + i) * (i + 1) + "\n"
writer.write(text)
import win32file
import os
import msvcrt
from io import open
handle = win32file.CreateFile(r"\\.\pipe\wfsr_pipe",
win32file.GENERIC_READ,
0, None,
win32file.OPEN_EXISTING,
0, None)
read_fd = msvcrt.open_osfhandle(handle, os.O_RDONLY)
with open(read_fd, "r") as reader:
# now we have a file object with the readlines and other file api methods
lines = reader.readlines()
print(lines)
Some notes. 一些注意事项。
read_fd
and write_fd
) with the os.O_RDWR
flag os.O_RDWR
标志创建文件描述符( read_fd
和write_fd
) "r+"
mode rather than "r"
or "w"
"r+"
模式而不是"r"
或"w"
模式创建文件对象 win32pipe.PIPE_ACCESS_DUPLEX
flag win32pipe.PIPE_ACCESS_DUPLEX
标志创建管道 win32file.GENERIC_READ | win32file.GENERIC_WRITE
win32file.GENERIC_READ | win32file.GENERIC_WRITE
创建文件句柄对象win32file.GENERIC_READ | win32file.GENERIC_WRITE
win32file.GENERIC_READ | win32file.GENERIC_WRITE
flags. win32file.GENERIC_READ | win32file.GENERIC_WRITE
标志。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.