使用命名管道时,是否有办法执行类似 readlines() 的操作
When working with a named pipe is there a way to do something like readlines()
总体目标:我正在尝试从 python exe 读取一些进度数据以更新另一个应用程序中 exe 的进度
我有一个要执行某些操作的 python exe,我希望能够将进度传达给另一个程序。基于这里的其他几个问答,我已经能够让我的 运行 应用程序使用以下代码
将进度数据发送到命名管道
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
"""
"""
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()
简而言之,示例代码将 glob 化的每个文件的路径写入 NamedPipe - 这很有用,并且可以轻松扩展到更多日志记录类型的事件。然而,问题是在不知道每条可能消息的大小的情况下,试图弄清楚如何读取命名管道的内容。例如,第一个文件可以命名为 J:\someDirectory\a.htm,但第二个文件的名称可以包含 300 个字符。
到目前为止,我用来读取管道内容的代码要求我指定缓冲区大小
首先建立连接
file_handle = win32file.CreateFile("\\.\pipe\wfsr_pipe",
win32file.GENERIC_READ | win32file.GENERIC_WRITE,
0, None,
win32file.OPEN_EXISTING,
0, None)
然后我一直在玩从文件中读取
data = win32file.ReadFile(file_handle,128)
这通常有效,但我真的想一直读到遇到一个换行符,对我开始阅读和换行符之间的内容做一些事情,然后重复这个过程,直到我到达 Process Complete 的一行在行
在找到换行符 (\n) 之前,我一直在为如何只读而苦恼。我基本上想按行读取文件并根据行的内容做一些事情(显示行或移动应用程序焦点)。
根据@meuh 提供的建议,我正在更新此内容,因为我认为缺少示例和如何使用管道的指南
我的服务器代码
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
"""
"""
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
客户端代码
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
我没有 windows 但通过 api 看来你应该转换
您的客户端通过在 CreateFile() 之后添加调用来进入消息模式:
win32pipe.SetNamedPipeHandleState(file_handle,
win32pipe.PIPE_READMODE_MESSAGE, None, None)
然后每个足够长的读取将 return 一条消息,即对方在一次写入中写的内容。您在创建管道时已经设置了 PIPE_TYPE_MESSAGE。
您可以简单地使用 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
注意:未经测试,但在修复最终的拼写错误后应该可以使用。
然后你可以这样做:
with PipeIO(file_handle) as fd:
for line in fd:
# process a line
您可以使用 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)
一些笔记。
- 我只用 python 3.4 测试过这个,但我相信你可能正在使用 python 2.x.
- Python 如果您尝试同时关闭文件对象和管道,似乎会变得很奇怪...,所以我只使用了文件对象(通过使用 with 块)
- 我只创建了文件对象以在一端读取并在另一端写入。您当然可以通过以下方式使文件对象双工
- 使用
os.O_RDWR
标志创建文件描述符(read_fd
和 write_fd
)
- 以
"r+"
模式而非 "r"
或 "w"
模式创建文件对象
- 返回使用
win32pipe.PIPE_ACCESS_DUPLEX
标志创建管道
- 返回使用
win32file.GENERIC_READ | win32file.GENERIC_WRITE
标志创建文件句柄对象。
总体目标:我正在尝试从 python exe 读取一些进度数据以更新另一个应用程序中 exe 的进度
我有一个要执行某些操作的 python exe,我希望能够将进度传达给另一个程序。基于这里的其他几个问答,我已经能够让我的 运行 应用程序使用以下代码
将进度数据发送到命名管道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
"""
"""
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()
简而言之,示例代码将 glob 化的每个文件的路径写入 NamedPipe - 这很有用,并且可以轻松扩展到更多日志记录类型的事件。然而,问题是在不知道每条可能消息的大小的情况下,试图弄清楚如何读取命名管道的内容。例如,第一个文件可以命名为 J:\someDirectory\a.htm,但第二个文件的名称可以包含 300 个字符。
到目前为止,我用来读取管道内容的代码要求我指定缓冲区大小
首先建立连接
file_handle = win32file.CreateFile("\\.\pipe\wfsr_pipe",
win32file.GENERIC_READ | win32file.GENERIC_WRITE,
0, None,
win32file.OPEN_EXISTING,
0, None)
然后我一直在玩从文件中读取
data = win32file.ReadFile(file_handle,128)
这通常有效,但我真的想一直读到遇到一个换行符,对我开始阅读和换行符之间的内容做一些事情,然后重复这个过程,直到我到达 Process Complete 的一行在行
在找到换行符 (\n) 之前,我一直在为如何只读而苦恼。我基本上想按行读取文件并根据行的内容做一些事情(显示行或移动应用程序焦点)。
根据@meuh 提供的建议,我正在更新此内容,因为我认为缺少示例和如何使用管道的指南
我的服务器代码
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
"""
"""
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
客户端代码
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
我没有 windows 但通过 api 看来你应该转换 您的客户端通过在 CreateFile() 之后添加调用来进入消息模式:
win32pipe.SetNamedPipeHandleState(file_handle,
win32pipe.PIPE_READMODE_MESSAGE, None, None)
然后每个足够长的读取将 return 一条消息,即对方在一次写入中写的内容。您在创建管道时已经设置了 PIPE_TYPE_MESSAGE。
您可以简单地使用 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
注意:未经测试,但在修复最终的拼写错误后应该可以使用。
然后你可以这样做:
with PipeIO(file_handle) as fd:
for line in fd:
# process a line
您可以使用 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)
一些笔记。
- 我只用 python 3.4 测试过这个,但我相信你可能正在使用 python 2.x.
- Python 如果您尝试同时关闭文件对象和管道,似乎会变得很奇怪...,所以我只使用了文件对象(通过使用 with 块)
- 我只创建了文件对象以在一端读取并在另一端写入。您当然可以通过以下方式使文件对象双工
- 使用
os.O_RDWR
标志创建文件描述符(read_fd
和write_fd
) - 以
"r+"
模式而非"r"
或"w"
模式创建文件对象
- 返回使用
win32pipe.PIPE_ACCESS_DUPLEX
标志创建管道 - 返回使用
win32file.GENERIC_READ | win32file.GENERIC_WRITE
标志创建文件句柄对象。
- 使用