with open("myfile", "rb") as f:
byte = f.read(1)
while byte:
# Do stuff with byte.
byte = f.read(1)
3
此生成器从文件中生成字节,以块的形式读取文件:
def bytes_from_file(filename, chunksize=8192):
with open(filename, "rb") as f:
while True:
chunk = f.read(chunksize)
if chunk:
for b in chunk:
yield b
else:
break
# example:
for b in bytes_from_file('filename'):
do_stuff_with(b)
bytes_read = open("filename", "rb").read()
for b in bytes_read:
process_byte(b)
其中process_byte表示要对传入的字节执行的某些操作 .
如果要一次处理一个块:
file = open("filename", "rb")
try:
bytes_read = file.read(CHUNKSIZE)
while bytes_read:
for b in bytes_read:
process_byte(b)
bytes_read = file.read(CHUNKSIZE)
finally:
file.close()
mmap允许您同时将文件视为bytearray和文件对象 . 如果您需要访问两个接口,它可以作为将整个文件加载到内存中的替代方法 . 特别是,您可以使用普通的 for -loop在内存映射文件上一次迭代一个字节:
from mmap import ACCESS_READ, mmap
with open(filename, 'rb', 0) as f, mmap(f.fileno(), 0, access=ACCESS_READ) as s:
for byte in s: # length is equal to the current file size
# Do stuff with byte
with open("myfile", "rb") as f:
while True:
byte = f.read(1)
if not byte:
break
do_stuff_with(ord(byte))
对于Python 2.6及更高版本,因为:
内部
python缓冲区 - 无需读取块
干燥原理 - 不要重复读取线
with语句可确保关闭文件 当没有更多字节时
'byte'的计算结果为false(而不是字节为零时)
或者使用J. F. Sebastians解决方案来提高速度
from functools import partial
with open(filename, 'rb') as file:
for byte in iter(partial(file.read, 1), b''):
# Do stuff with byte
或者如果你想将它作为代码表示的生成器函数:
def bytes_from_file(filename):
with open(filename, "rb") as f:
while True:
byte = f.read(1)
if not byte:
break
yield(ord(byte))
# example:
for b in bytes_from_file('filename'):
do_stuff_with(b)
import pathlib
for byte in pathlib.Path(path).read_bytes():
print(byte)
有趣的是,这是唯一提到 pathlib 的答案 .
在Python 2中,你可能会这样做(正如Vinay Sajip也建议的那样):
with open(path, 'b') as file:
for byte in file.read():
print(byte)
如果文件可能太大而无法在内存中进行迭代,那么您可以使用带有 callable, sentinel 签名的 iter 函数(Python 2版本)以惯用方式对其进行分块:
with open(path, 'b') as file:
callable = lambda: file.read(1024)
sentinel = bytes() # or b''
for chunk in iter(callable, sentinel):
for byte in chunk:
print(byte)
(其他几个答案提到了这一点,但很少有人提供合理的读取大小 . )
大文件或缓冲/交互式阅读的最佳实践
让我们创建一个执行此操作的函数,包括Python 3.5标准库的惯用用法:
from pathlib import Path
from functools import partial
from io import DEFAULT_BUFFER_SIZE
def file_byte_iterator(path):
"""given a path, return an iterator over the file
that lazily loads the file
"""
path = Path(path)
with path.open('rb') as file:
reader = partial(file.read1, DEFAULT_BUFFER_SIZE)
file_iterator = iter(reader, bytes())
for chunk in file_iterator:
for byte in chunk:
yield byte
from array import array
with open( path, 'rb' ) as file:
data = array( 'B', file.read() ) # buffer the file
# evaluate it's data
for byte in data:
v = byte # int value
c = chr(byte)
如果你想迭代字符而不是整数,你可以简单地使用 data = file.read() ,它应该是py3中的bytes()对象 .
9 回答
Python 3,一次读取所有文件:
您可以使用
data
变量迭代任何您想要的内容 .如果要读取大量二进制数据,可能需要考虑struct module . 它被记录为转换"between C and Python types",但当然,字节是字节,并且这些是否是作为C类型创建并不重要 . 例如,如果二进制数据包含两个2字节整数和一个4字节整数,则可以按如下方式读取它们(示例来自
struct
文档):您可能会发现这比显式循环文件内容更方便,更快捷或两者兼而有之 .
Python 2.4 and Earlier
Python 2.5-2.7
请注意,with语句在2.5以下的Python版本中不可用 . 要在v 2.5中使用它,您需要导入它:
在2.6中,这不是必需的 .
Python 3
在Python 3中,它有点不同 . 我们将不再以字节模式从流中获取原始字符,而是字节对象,因此我们需要更改条件:
或者正如benhoyt所说,跳过不等于并利用
b""
评估为假的事实 . 这使代码在2.6和3.x之间兼容,无需任何更改 . 如果从字节模式转换为文本或反向,它还可以避免更改条件 .此生成器从文件中生成字节,以块的形式读取文件:
有关iterators和generators的信息,请参阅Python文档 .
如果文件不是太大,将其保存在内存中就是一个问题:
其中process_byte表示要对传入的字节执行的某些操作 .
如果要一次处理一个块:
要读取文件 - 一次一个字节(忽略缓冲) - 您可以使用two-argument iter(callable, sentinel) built-in function:
它调用
file.read(1)
直到它不返回b''
(空字节串) . 对于大文件,内存不会无限增长 . 您可以将buffering=0
传递给open()
,以禁用缓冲 - 它保证每次迭代只读取一个字节(慢) .with
-statement自动关闭文件 - 包括下面的代码引发异常的情况 .尽管默认情况下存在内部缓冲,但一次处理一个字节仍然是低效的 . 例如,这是
blackhole.py
实用程序,它会占用它给出的所有内容:例:
它在我的机器上
chunksize == 32768
时处理~1.5 GB / s,在chunksize == 1
时仅处理~7.5 MB / s . 也就是说,一次读取一个字节要慢200倍 . 如果您可以重写处理以一次使用多个字节并且需要性能,请将其考虑在内 .mmap允许您同时将文件视为bytearray和文件对象 . 如果您需要访问两个接口,它可以作为将整个文件加载到内存中的替代方法 . 特别是,您可以使用普通的
for
-loop在内存映射文件上一次迭代一个字节:mmap
支持切片表示法 . 例如,mm[i:i+len]
从位置i
开始的文件返回len
个字节 . Python 3.2之前不支持上下文管理器协议;在这种情况下,您需要显式调用mm.close()
. 使用mmap
迭代每个字节会消耗比file.read(1)
更多的内存,但mmap
的速度要快一个数量级 .总结一下chrispy,Skurmedel,Ben Hoyt和Peter Hansen的所有优点,这将是一次一个字节处理二进制文件的最佳解决方案:
对于Python 2.6及更高版本,因为:
内部
python缓冲区 - 无需读取块
干燥原理 - 不要重复读取线
with语句可确保关闭文件
当没有更多字节时
'byte'的计算结果为false(而不是字节为零时)
或者使用J. F. Sebastians解决方案来提高速度
或者如果你想将它作为代码表示的生成器函数:
Python 3.5中的新功能是
pathlib
模块,它有一个特别方便的方法来读取文件中的字节,允许我们迭代字节 . 我认为这是一个体面的(如果快速和肮脏)答案:有趣的是,这是唯一提到
pathlib
的答案 .在Python 2中,你可能会这样做(正如Vinay Sajip也建议的那样):
如果文件可能太大而无法在内存中进行迭代,那么您可以使用带有
callable, sentinel
签名的iter
函数(Python 2版本)以惯用方式对其进行分块:(其他几个答案提到了这一点,但很少有人提供合理的读取大小 . )
大文件或缓冲/交互式阅读的最佳实践
让我们创建一个执行此操作的函数,包括Python 3.5标准库的惯用用法:
请注意,我们使用
file.read1
.file.read
阻塞,直到它获得所请求的所有字节或EOF
.file.read1
允许我们避免阻塞,因此可以更快地返回 . 没有其他答案也提到这一点 .演示最佳实践用法:
让我们创建一个具有兆字节(实际上是mebibyte)的伪随机数据的文件:
现在让我们迭代它并在内存中实现它:
我们可以检查数据的任何部分,例如,最后100个字节和前100个字节:
不要按行迭代二进制文件
不要执行以下操作 - 这会拉出任意大小的块直到它到达换行符 - 当块太小时太慢,并且可能太大:
以上只适用于语义上人类可读的文本文件(如纯文本,代码,标记,降价等...基本上任何ascii,utf,latin等编码) .
如果你正在寻找快速的东西,这是我一直使用的方法多年来一直工作:
如果你想迭代字符而不是整数,你可以简单地使用
data = file.read()
,它应该是py3中的bytes()对象 .