如何将原始文件系统的大部分复制到文件?

时间:2018-03-17 02:23:56

标签: 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:
        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直接复制不起作用。 (我假设)无法指定结束位置,因此副本不会停止。

以下是一些问题,每个问题都可以解决这个问题:

  • 是否有一个副本库(或Windows 7的外部实用程序,可用于subprocess),它接受开始/结束字节参数?
  • 是否可以创建copyfileobj可以使用的类似文件的对象,它只引用另一个类文件对象的一部分?
  • io对象寻求超过某个终点时,是否可以引发异常?
  • copyfileobj是否可以强制在驱动器的给定字节偏移处自然停止(某种“假EOF”)?

1 个答案:

答案 0 :(得分:2)

显而易见的方法是只对文件write

copyfileobj的重点是它为您缓冲数据。如果您必须将整个文件读入BytesIO,那么您只需缓冲BytesIO,这是毫无意义的。

所以,只需从readsrc_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)