Python 如何将原始文件系统的很大一部分复制到文件中?
我正在使用一个神秘的数据收集文件系统。它有一个描述文件及其在磁盘上的精确偏移量的块,所以我知道每个文件的开始字节、结束字节和长度(以字节为单位)。目标是从物理磁盘中获取一个文件。它们是大文件,因此性能至关重要 以下是“有效”但效率很低的方法:Python 如何将原始文件系统的很大一部分复制到文件中?,python,windows,filesystems,buffer,disk,Python,Windows,Filesystems,Buffer,Disk,我正在使用一个神秘的数据收集文件系统。它有一个描述文件及其在磁盘上的精确偏移量的块,所以我知道每个文件的开始字节、结束字节和长度(以字节为单位)。目标是从物理磁盘中获取一个文件。它们是大文件,因此性能至关重要 以下是“有效”但效率很低的方法: import shutil, io def start_copy(startpos, endpos, filename="C:\\out.bin"): with open(r"\\.\PhysicalDrive1", 'rb') as src_f:
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\u f
直接复制将不起作用。(我假设)无法指定结束位置,因此复制不会停止
以下是一些问题,每个问题都可以解决:
- 是否有采用起始/结束字节参数的复制库(或Windows 7的外部实用程序,可与
)一起使用子流程
- 是否可以创建一个
可以使用的类似文件的对象,它只引用另一个类似文件的对象的一部分copyfileobj
- 当
对象搜索超过某个端点时,是否可以引发异常io
是否可以强制在驱动器的给定字节偏移量(一种“伪EOF”)处自然停止copyfileobj
写入文件
copyfileobj
的全部要点是为您缓冲数据。如果必须将整个文件读入BytesIO
,则只需缓冲BytesIO
,这是毫无意义的
因此,只需从src_f
循环read
ing一个适当大小的缓冲区,然后write
将其写入dst_f
,直到达到flength
字节
如果你看一下(链接自),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)
def copypartialfileobj(fsrc、fdst、大小、长度=16*1024):
“”“将大小字节从类文件对象fsrc复制到类文件对象fdst”“”
写入=0
书写时<大小:
buf=fsrc.read(最小值(长度、大小-写入))
如果不是buf:
打破
fdst写入(buf)
写入+=长度(buf)
为什么您需要使用copyfileobj
而不仅仅是写入
?@charjabug它不是异步工作的,而是由操作系统(以及驱动程序和驱动器电路)完成的缓冲这意味着,只要你按顺序在大小合适的块中阅读,它就可以很好地进行管道化处理。@charjabug如果你需要进一步加速,异步可能不是关键,至少不是直接的。如果其中一个磁盘是SSD或宽RAID条带(因此寻道时间不会像普通硬盘驱动器那样比吞吐量慢得可怕),只需执行4个线程,每个线程复制文件的1/4,就可以加快速度。或者,您可以使用pywin32
调用一些适当的Win32 API函数,尽管我认为您必须处理重叠的I/O以获得任何加速。@charjabug另外,Python的大量stdlib模块被设计为可用的示例代码,而不仅仅是现成的工具。如果您转到任何模块的文档,并且有一个指向源代码的链接,单击它,您可以确切地看到它的工作原理。@charjabug我认为读一次写两次应该会更快…但不会那么快。毕竟,这是在优化过程中最快的部分(读取SSD,甚至可能从其缓存中取出),而不会影响最慢的部分(写入机械驱动器)。但是,并行执行两个副本(A->A&B->B同时在两个线程上执行,然后A->B和B->A在两个线程上执行)可以将您的时间减少近一半。(取决于总线争用是否与mechanical HD速度一样接近瓶颈,但我会尝试一下。)如果您已经知道目标文件大小,可以使用fdst.truncate(size)
;内存通过mdst=mmap.mmap(fdst.fileno(),0)映射目标;然后通过fsrc.readinto(mdst)
复制数据。