如何以几个同时的块下载一个大文件并将其保存到Python中的同一文件中?

时间:2019-10-18 15:52:41

标签: python multithreading file download chunks

我使用的是PyCurl,范围为http的标头和Python线程,因此,如果我需要下载1 gb文件并想使用例如与服务器的5条连接来加快处理速度,我将1 gb分为五个部分,并创建五个线程,每个线程下载1/5,然后将1/5保存到“ .part”文件中,当5个线程全部完成并下载其1/5文件时,我只需加入所有部分并重新创建1 GB档案。

我的问题是:我如何以相同的5个块下载文件,而不是将每个块保存到临时文件中,然后将所有文件都合并到原始文件中,只需下载5个部分并将这些部分保存到直接一个1gb文件?这可能吗?

2 个答案:

答案 0 :(得分:2)

因此,正如我们在评论中讨论的那样,您不能真的做您想做的事情。不过,我有几个想法可能会对您有所帮助。

选项1

如果您知道要下载的文件大小,则可以创建所需大小的文件,并用下载的字节覆盖。

with open("some_file_name", "wb") as f:
    f.truncate(some_size)

with open("some_file_name", "wb") as f:
    f.seek(some_size - 1)
    f.write('\0')

请注意,如果指定的大小超过文件的当前大小,则结果取决于平台:可能包括文件可能保持不变,增大为指定的大小(好像是零填充的)或增大为指定的大小大小以及未定义的新内容。

因此,在下载部分时,您可以使用来覆盖特定的字节块

with open("some_file_name", "r+b") as f:
    f.seek(offset)
    f.write(data_chunk)

选项2

确定您愿意使用多少内存,一次只能下载一定数量的部件。

示例:如果您决定只使用1GB,并且要下载250 MB的大文件

  • 开始并行下载前4个块。
  • 块1完成下载后,您可以将其写入磁盘并开始下载块5。
  • 如果一个块在较低的块(例如2在1之前完成)之前完成下载,则将其保存在内存中,直到另一个块完成为止。
  • 这将内存使用量限制为1 GB,因为一次下载的块不超过四个250 MB。

选项3

写入临时文件(如您在原始问题中提到的那样),但将其保存在用户可能看不到它们的位置,例如系统的temp目录或程序创建的隐藏目录中

答案 1 :(得分:1)

至少在Unix / Linux系统上,您应该能够轻松地做到这一点。关键是您应该在线程1中创建一次文件,然后将其打开以进行写入。然后,您需要再重新打开个文件N次以上(也用于写操作,但绝不用于附加操作),以便为每个要使用的线程获得一个独立的文件描述符。

接下来,使用其自己的文件描述符将每个线程lseek移至文件中的适当起始位置,然后从服务器接收到后,它就可以开始将大块写入文件中。 (只要您使用的是二进制I / O,您也应该能够使用标准的python文件对象及其seek方法。)

之所以起作用,是因为每个文件描述符都有一个独立的文件指针,并且在所有的UNIX系统上,文件指针应在编写时自动前进。而且,文件中没有空隙也没有问题;操作系统应该可以处理。

IOW,用于具有5个线程的1GB文件:

thread 1, fd 1, position 0 (writing through 200MB-1)
thread 2, fd 2, position 200MB (through 400MB-1)
...
thread 5, fd 5, position 800MB (through 1GB-1)

python中的线程代码(假设您已经在主线程中创建了文件)可以很简单:

with open("the_file", "r+b") as myfile:   # open for update
    myfile.seek(my_starting_pos)
    while ...:
         next_chunk = recv_from_server()
         myfile.write(next_chunk)