我正在使用一个神秘的数据收集文件系统。它有一个块描述文件及其在磁盘上的确切偏移量,因此我知道每个文件的起始字节,结束字节和长度(以字节为单位)。目标是从物理磁盘中获取一个文件。它们是大文件,因此性能至关重要。
这是“有效”,但非常低效:
import shutil, io
def start_copy(startpos, endpos, filename="C:\\out.bin"):
with open(r"\\.\PhysicalDrive1", 'rb') as src_f:
src_f.seek(startpos)
flength = endpos - startpos
print("Starting copy of "+filename+" ("+str(flength)+"B)")
with open(filename, 'wb') as dst_f:
shutil.copyfileobj( io.BytesIO(src_f.read(flength)), dst_f )
print("Finished copy of "+filename)
这很慢:io.BytesIO(src_f.read(flength))
在技术上有效,但它在写入目标文件之前将整个文件读入内存。所以它需要的时间比它应该的长。
使用dst_f
直接复制不起作用。 (我假设)无法指定结束位置,因此副本不会停止。
以下是一些问题,每个问题都可以解决这个问题:
subprocess
),它接受开始/结束字节参数?copyfileobj
可以使用的类似文件的对象,它只引用另一个类文件对象的一部分?io
对象寻求超过某个终点时,是否可以引发异常?copyfileobj
是否可以强制在驱动器的给定字节偏移处自然停止(某种“假EOF”)?答案 0 :(得分:2)
显而易见的方法是只对文件write
。
copyfileobj
的重点是它为您缓冲数据。如果您必须将整个文件读入BytesIO
,那么您只需缓冲BytesIO
,这是毫无意义的。
所以,只需从read
和src_f
write
循环dst_f
一个体积适中的缓冲区,直到达到flength
个字节。
如果你看the shutil
source(从the shutil
docs链接),copyfileobj
内就没有魔法了;这是一个微不足道的功能。从3.6开始(我认为自shutil
添加到2.1左右以来它完全没有变化),它看起来像这样:
def copyfileobj(fsrc, fdst, length=16*1024):
"""copy data from file-like object fsrc to file-like object fdst"""
while 1:
buf = fsrc.read(length)
if not buf:
break
fdst.write(buf)
您可以执行相同的操作,只需跟踪在flength
处读取和停止的字节:
def copypartialfileobj(fsrc, fdst, size, length=16*1024):
"""copy size bytes from file-like object fsrc to file-like object fdst"""
written = 0
while written < size:
buf = fsrc.read(min(length, size - written))
if not buf:
break
fdst.write(buf)
written += len(buf)