我有这个代码:
import sys
binfile = "data.hex"
print("Paste ascii encoded data.")
line = sys.stdin.readline()
b = bytes.fromhex(line)
with open(binfile, "wb") as fp:
fp.write(b)
问题是在
sys.stdin.readline()
调用中读取的字节数永远不会超过 4096 个字节。我怎样才能使缓冲区更大?我尝试为呼叫提供更大的号码,但这没有效果。
更新我将我的
stdin
阅读代码更改为:
line = ''
while True:
b = sys.stdin.read(1)
sys.stdin.flush()
line += b
if b == "\n":
break
print(f"Read {len(line)} bytes")
仍然会遇到这个限制。
这种将长行截断为 4096 字节的行为是由 Linux 内核中的 TTY 代码引起的。对于您的用例,即当将长行复制粘贴到终端窗口时,没有简单的修复方法。作为解决方法,请复制粘贴到文件(例如
infile.dat
),然后运行 python script.py <infile.dat
。
即使没有 Python,您也可以通过运行
dd bs=65536 of=/dev/null
来重现它,复制粘贴长度超过 4096 字节的行,然后按 Ctrl-D 来指示 EOF。输出的最后一行将以 4096 bytes (4.1 kB, 4.0 KiB) copied,
开头,表示仅读取了 4096 字节。如果您复制粘贴多行长行,您会发现每行都会被分别截断为 4096 字节(包括换行符字节)。
我的答案的其余部分演示了 Python 和 shell(例如 Bash)如何在没有截断的情况下工作,因此它们不会导致问题。
这是为了证明 Python
sys.stderr.readline()
不会截断。
Python
sys.stdin.readline()
是无限的(假设有足够的可用内存)。我已经在 Linux 上使用 Python 2.7、3.6 和更新版本的 Python 进行了尝试。
这是我尝试过的:
立即从管道读取短行(Python 中没有额外的缓冲延迟):
$ (echo -n A; sleep .3; echo a; sleep .3; echo B; sleep .3) | python -c "if 1:
for line in iter(__import__('sys').stdin.readline, ''): print([line])"
['Aa\n']
['B\n']
要尝试一下,请运行不带前导
$
的命令。它对我来说适用于 Linux,我认为它也适用于 macOS、Windows 和其他系统。在 Windows 上,您可能需要删除 if 1:
和换行符。
仅供参考,要防止缓冲延迟,请使用
for line in iter(sys.stdin.readline, ''):
(如上所述)而不是for line in sys.stdin:
。有关详细信息,请参阅 https://stackoverflow.com/a/28919832/97248 和其他答案。
在 Python 3.x 中,使用
sys.stdin.buffer.readline()
: 立即从管道中将短行读取为字节(而不是 Unicode 字符)
$ (echo -n A; sleep .3; echo a; sleep .3; echo B; sleep .3) | python -c "if 1:
for line in iter(__import__('sys').stdin.buffer.readline, b''): print([line])"
[b'Aa\n']
[b'B\n']
要尝试一下,请运行不带前导
$
的命令。它对我来说适用于 Linux,我认为它也适用于 macOS、Windows 和其他系统。在 Windows 上,您可能需要删除 if 1:
和换行符。
立即从管道读取长(超过 10 MiB)行:
$ python -c "if 1:
import sys, time; f = sys.stdout
f.write('A' * 10987654); f.flush(); time.sleep(.3)
f.write('aaa\n'); f.flush(); time.sleep(.3)
f.write('B\n'); f.flush(); time.sleep(.3)" |
python -c "if 1:
for line in iter(__import__('sys').stdin.readline, ''): print(len(line))"
10987658
2
要尝试一下,请运行不带前导
$
的命令。它对我来说适用于 Linux,我认为它也适用于 macOS、Windows 和其他系统。在 Windows 上,将 Python 代码放入文件 a.py
和 b.py
,然后运行 python a.py | python b.py
。
立即从 PTY(终端)读取长(超过 10 MiB)行:
$ python -c "if 1:
import sys, time; f = sys.stdout
f.write('A' * 10987654); f.flush(); time.sleep(.3)
f.write('aaa\n'); f.flush(); time.sleep(.3)
f.write('B\n'); f.flush(); time.sleep(.3)" |
python -c "if 1:
for line in iter(__import__('sys').stdin.readline, ''): print(len(line))"
10987658
2
这证明不是 shell 导致了截断。
TODO(分):写这个。