2

我正在编写一个程序,它可以从多个不同的服务器一次下载多个文件(当然,每个服务器一个下载线程!)。我担心磁盘上同时增长的多个文件会导致磁盘碎片,我想通过Content-Length在开始下载之前为整个文件的长度(如标题所报告的)预先分配磁盘空间来缓解这种情况,理想情况下不增加文件的表观长度(所以我可以通过以附加模式打开部分下载的文件来恢复失败的下载)。

这可能以独立于平台的方式吗?

4

2 回答 2

1

我做了一些谷歌搜索,发现这篇带有一些 C 代码的可爱文章可以完全按照您在 Windows 上的要求进行操作。这是翻译成的 C 代码ctypes(为便于阅读而编写):

    import ctypes
    import msvcrt
    # https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle
    set_file_information = ctypes.windll.kernel32.SetFileInformationByHandle

    class AllocationInfo(ctypes.Structure):
        _fields_ = [('AllocationSize', ctypes.c_longlong)]
    
    def allocate(file, length):
        """Tell the filesystem to preallocate `length` bytes on disk for the specified `file` without increasing the
        file's length.
        In other words, advise the filesystem that you intend to write at least `length` bytes to the file.
        """
        allocation_info = AllocationInfo(length)
        retval = set_file_information(ctypes.c_long(msvcrt.get_osfhandle(file.fileno())),
                                      ctypes.c_long(5),  # constant for FileAllocationInfo in the FILE_INFO_BY_HANDLE_CLASS enum
                                      ctypes.pointer(allocation_info),
                                      ctypes.sizeof(allocation_info)
                                      )
        if retval != 1:
            raise OSError('SetFileInformationByHandle failed')

这将更改文件在磁盘上的大小:如文件资源管理器中所示为您指定的长度(加上几千字节的元数据),但保持大小:不变。

然而,在我用谷歌搜索的半个小时里,我还没有找到在 POSIX 上做到这一点的方法。 fallocate()实际上与您所追求的完全相反:它将文件的表观长度设置为您给它的长度,但将其分配为磁盘上的稀疏范围,因此同时写入多个文件仍会导致碎片。具有讽刺意味的是,Windows 具有 POSIX 所缺乏的文件管理功能,不是吗?

我只希望被证明是错误的,但我认为这是不可能的。

于 2020-08-06T01:55:47.807 回答
0
FILENAME = "somefile.bin"
SIZE = 4200000

with open(FILENAME, "wb") as file:
    file.seek(SIZE - 1)
    file.write(b"\0")

优点:

  1. 可在所有平台上移植。
  2. 如果您正在mmap(内存映射)文件以对其执行写入(MADV_SEQUENTIAL如果需要顺序访问),则非常有效。
于 2021-06-23T17:07:47.030 回答