簡體   English   中英

subprocess.Popen 標准輸入讀取文件

[英]subprocess.Popen stdin read file

我正在嘗試在讀取文件的一部分后調用文件的進程。 例如:

with open('in.txt', 'r') as a, open('out.txt', 'w') as b:
  header = a.readline()
  subprocess.call(['sort'], stdin=a, stdout=b)

如果我在執行 subprocess.call 之前沒有從 a 中讀取任何內容,這將正常工作,但是如果我從中讀取任何內容,則子流程將看不到任何內容。 這是使用 python 2.7.3。 我在文檔中找不到任何解釋這種行為的內容,並且(非常)簡短地瀏覽了子流程源並沒有發現原因。

如果您無緩沖地打開文件,則它可以工作:

import subprocess

with open('in.txt', 'rb', 0) as a, open('out.txt', 'w') as b:
    header = a.readline()
    rc = subprocess.call(['sort'], stdin=a, stdout=b)

subprocess模塊在文件描述符級別(操作系統的低級別無緩沖 I/O)工作。 如果操作系統支持,它可以與os.pipe()socket.socket()pty.openpty()以及任何具有有效.fileno()方法的東西一起使用。

不建議在同一個文件上混合緩沖和非緩沖 I/O。

在 Python 2 上, file.flush()導致輸出出現,例如:

import subprocess
# 2nd
with open(__file__) as file:
    header = file.readline()
    file.seek(file.tell()) # synchronize (for io.open and Python 3)
    file.flush()           # synchronize (for C stdio-based file on Python 2)
    rc = subprocess.call(['cat'], stdin=file)

這個問題可以不被復制subprocess模塊os.read()

#!/usr/bin/env python
# 2nd
import os

with open(__file__) as file: #XXX fully buffered text file EATS INPUT
    file.readline() # ignore header line
    os.write(1, os.read(file.fileno(), 1<<20))

如果緩沖區大小很小,則打印文件的其余部分:

#!/usr/bin/env python
# 2nd
import os

bufsize = 2 #XXX MAY EAT INPUT
with open(__file__, 'rb', bufsize) as file:
    file.readline() # ignore header line
    os.write(2, os.read(file.fileno(), 1<<20))

如果第一行的大小不能被bufsize整除,它會消耗更多的輸入。

默認的bufsizebufsize=1 (行緩沖)在我的機器上表現相似:文件的開頭消失了——大約 4KB。

file.tell()報告所有緩沖區大小的第 2 行開頭的位置。 由於預讀緩沖區錯誤io.open()給出了預期的第 2 行位置),使用next(file)而不是file.readline()在我的 Python 2 機器上導致file.tell()大約 5K。

在子file.seek(file.tell())調用之前嘗試file.seek(file.tell())對具有默認基於 stdio 的文件對象的 Python 2 沒有幫助。 它與 Python 2 上的io_pyio模塊中的open()函數以及 Python 3 上的默認open (也是基於io的)一起使用。

使用和不使用file.flush()在 Python 2 和 Python 3 上嘗試io_pyio模塊會產生各種結果。 它確認在同一個文件描述符上混合緩沖和非緩沖 I/O 不是一個好主意

這是因為子進程模塊從文件對象中提取文件句柄。

http://hg.python.org/releasing/2.7.6/file/ba31940588b6/Lib/subprocess.py

在第 1126 行,來自 701。

文件對象使用緩沖區,並且在子進程提取文件句柄時已經從文件句柄中讀取了很多內容。

正如@jfs 提到的,在使用 popen 時,它會將文件描述符傳遞給進程,同時 python 讀取塊(例如 4096 字節),結果是 fd 級別的位置與您期望的不同。

我通過對齊文件描述符位置在 python 2.7 中解決了它。

_file = open(some_path)
_file.read(codecs.BOM_UTF8)
os.lseek(_file.fileno(), _file.tell(), os.SEEK_SET)
truncate_null_cmd = ['tr','-d', '\\000']
subprocess.Popen(truncate_null_cmd, stdin=_file, stdout=subprocess.PIPE)

暫無
暫無

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

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