簡體   English   中英

使用命名管道時,有沒有辦法做類似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
""" 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()

簡而言之,示例代碼將每個文件的路徑寫入到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
""" 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

客戶端代碼

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)

那么每次足夠長的讀取將返回一條消息,即另一條消息在一次寫入中所寫的內容。 創建管道時,您已經設置了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進行了測試,但是我相信您可能正在使用python2.x。
  • 如果您嘗試同時關閉文件對象和管道,Python似乎會變得很奇怪...,所以我只使用了文件對象(通過使用with塊)
  • 我只創建了要在一端讀取並在另一端寫入的文件對象。 您當然可以通過以下方式使文件對象成為雙工
    • 使用os.O_RDWR標志創建文件描述符( read_fdwrite_fd
    • "r+"模式而不是"r""w"模式創建文件對象
    • 返回到使用win32pipe.PIPE_ACCESS_DUPLEX標志創建管道
    • 返回到使用win32file.GENERIC_READ | win32file.GENERIC_WRITE創建文件句柄對象win32file.GENERIC_READ | win32file.GENERIC_WRITE win32file.GENERIC_READ | win32file.GENERIC_WRITE標志。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM