python大文件分段下载器
本次使用到的技术点:大文件分割、多线程下载同一个文件、队列管理待下载文件片段、os.path模块管理本地文件、requests请求下载视频
一、项目由来
网上很少关于python使用多线程分段下载超清视频、大文本等超大文件的资料,由于多线程适合io密集型和网络请求,所以使用多线程下载大文件能极大的提高下载效率。本次需求产生的原因是朋友在做视频爬取项目,已经提取到了视频下载地址的情况下产生的,由于需要下载大量的视频,使用单线程下载速度极慢,又没有使用scrapy框架,所以本人就想着开辟多线程下载视频,于是写好了一个多线程下载视频的文件,但是由于下载的都是超清视频,下载速度还是不够快,本人就想到了将文件分段下载再合成,使用多线程下载一个文件不就又比单线程下载一个文件快了吗,估计迅雷也是这样实现的吧。
二、下载思路
- 获取要下载的视频的大小
- 将视频大小分割成N段每次每段的大小为1M(1024*1024)
- 将每段加入队列,开启多线程请求获取每段文件保存到本地
- 所有的文件片段下载完成将文件片段合成
三、具体实现
本次需要构建两个类
- 文件管理类FileManger
文件管理类FileManger类,负责文件的管理(分割文件、保存文件、合成文件片段、创建文件目录、获取本地保存文件片段编号列表等)
文件管理类使用多线程保存文件、使用os.path模块管理文件
-
下载器类Downloader
下载器类主要用于发送网络请求,分段获取视频文件,通过文件管理类将文件片段保存到本地并合成。
四、技术点要点
- 文件分割
def split_file(self, start=0, end=None, section_size=1024 * 1024):
"""
分割文件
:param start:开始位置,默认从头开始
:param end: 结束位置,默认到文件末尾
:param section_size: 分割片段的大小,默认为1M
:return: 字典格式,段数count及片段列表sections
"""
if end:
# 用户定义了分割大小
end = end
elif os.path.exists(self.file_path):
# 用户未定义分割大小,系统存在文件
end = os.path.getsize(self.file_path)
else:
# 其他情况
return False
if end < start:
# 末尾大于开始
return False
# 获取分割段数
n = (end - start) // section_size + 1
# 分割文件,将分割结果加入下载队列中
sections = {str(i): (i * section_size, (i + 1) * section_size - 1 if i + 1 != n else end - start) for i in
range(n)}
return sections
- 文件合成
def merge_section(self, path=None, count=None):
"""
合并本地的文件片段
:param path: 本地片段所在目录
:return: boolean
"""
# 获取当前管理的文件的文件夹名
path = path if path else os.path.splitext(self.file_path)[0]
index = 0
# print(path)
if not os.path.isdir(path):
# 文件夹不存在
return False
# 创建一个文件字典
file = dict()
file_size = 0
file_name = ""
for root, dirs, names in os.walk(path):
for name in names:
# 获取后缀名
id, ext = os.path.splitext(name)
# 获取所有具有编号的mp4文件
if ext == '.mp4' and id.isdigit():
# print(name)
# mp4文件原始地址
section_path = os.path.join(root, name)
# print(type(section_path), section_path)
file[id] = section_path
file_size += os.path.getsize(section_path)
file_name = os.path.join(path, f"{os.path.split(path)[-1]}{ext}")
# 没有获取到文件
if len(file.keys()) <= 0:
return False
# 如果用户输入count使用用户的count数
count = count if count else len(file.keys())
if count > len(file.keys()):
# 若用户输入的count大于实际的文件数,使用实际的文件数
count = len(file.keys())
file_size = 0
for i in range(count):
# 重新获取文件的大小
file_size += os.path.getsize(file.get(str(i)))
if os.path.exists(file_name):
# 文件已经合成完毕
if os.path.getsize(file_name) >= file_size:
# print("文件已经合成完毕,不需要再次合成")
return False
while index < count:
# 打开本地文件获取文件片段,合并文件片段
path = file.get(str(index))
if path == None:
print(f"未找到文件编号:{index}")
break
# 获取数据将数据写入本地
f = open(path, mode="rb")
data = f.read()
file_path = os.path.join(os.path.splitext(self.file_path)[0], os.path.basename(self.file_path))
fp = open(file_path, mode="ab")
fp.write(data)
fp.close()
f.close()
index += 1
- 文件多线程保存
def save_section(self, section_dict):
"

介绍了一种使用Python实现的多线程大文件分段下载技术,该技术适用于超清视频、大文本等超大文件的高效下载。通过将文件分割成小块并利用多线程同时下载各个部分,最后合并成完整文件,显著提高了下载速度。
最低0.47元/天 解锁文章
491

被折叠的 条评论
为什么被折叠?



