Python 工具类实现大文件断点续传功能详解

yizhihongxing

Python 工具类实现大文件断点续传功能详解

简介

在文件上传或下载过程中,如果遇到大文件,如果发生传输失败,需要重新传输的情况会非常不方便,甚至无法实现。为了解决这种问题,我们可以实现大文件断点续传功能,使文件上传或下载可以随时中断和恢复。

实现流程

大文件断点续传的实现流程如下:

  1. 设置支持 range 的Range头,支持服务器返回指定范围的数据。

  2. 获取已下载或已上传的文件大小,作为Range头的值发送给服务器。

  3. 将请求的数据写入到文件中,同时记录已下载或已上传的文件大小,作为下次请求的Range头的值。

  4. 如果请求发生中断,下次请求的Range头的值应为已下载或已上传的文件大小。

  5. 下一次请求时,从已下载或已上传的文件大小处开始请求即可。

示例说明

下面分两个示例说明大文件断点续传功能的实现。

示例1:大文件上传

在文件上传过程中,如果上传过程中出现中断,可以实现大文件上传的断点续传功能。

import requests

class FileUploader():
    def __init__(self, url):
        self.url = url
        self.chunk_size = 1024*1024*10

    def upload(self, file_path):
        with open(file_path, 'rb') as f:
            size = os.path.getsize(file_path)
            start = 0
            # 读取上次上传的位置
            if os.path.exists(f'{file_path}.cur'):
                with open(f'{file_path}.cur', 'r') as cf:
                    start = int(cf.read())
            f.seek(start)
            while start < size:
                end = min(start + self.chunk_size, size)
                data = f.read(self.chunk_size)
                headers = {'Content-Range': f'bytes {start}-{end-1}/{size}'}
                response = requests.put(self.url, headers=headers, data=data)
                if response.status_code == 200 or response.status_code == 201:
                    # 保存上传位置
                    with open(f'{file_path}.cur', 'w') as cf:
                        cf.write(str(end))
                    start = end
                else:
                    print(f'Error! status_code: {response.status_code}')

if __name__ == '__main__':
    uploader = FileUploader('http://xxx.com/file')
    uploader.upload('bigfile.zip')

上述代码中,我们定义了一个 FileUploader 类,其中 chunk_size 表示单次上传的大小,文件上传的范围使用 Content-Range 头指定,上传前先读取上次上传的位置,然后将已上传的位置写入到文件中。

示例2:大文件下载

在文件下载过程中,如果下载过程中出现中断,可以实现大文件下载的断点续传功能。

import requests
import os

class FileDownloader():
    def __init__(self, url, file_path):
        self.url = url
        self.file_path = file_path
        self.chunk_size = 1024*1024*10

    def download(self):
        headers = {}
        if os.path.exists(self.file_path):
            start = os.path.getsize(self.file_path)
            headers = {'Range': f'bytes={start}-'}
            print(f'Resumable mode: start download from {start}')
        else:
            start = 0
            print('Normal mode: start download from beginning')
        response = requests.get(self.url, headers=headers, stream=True)
        with open(self.file_path, 'ab') as f:
            total_size = int(response.headers.get('content-length', start))
            for chunk in response.iter_content(chunk_size=self.chunk_size):
                if chunk:
                    f.write(chunk)
                    f.flush()
            print('Download success!')

if __name__ == '__main__':
    downloader = FileDownloader('http://xxx.com/bigfile.zip', 'bigfile.zip')
    downloader.download()

上述代码中,我们定义了一个 FileDownloader 类,其中文件下载的范围使用 Range 头指定,下载前先读取已下载的文件大小,然后使用追加模式打开文件,将读取到的数据写入到文件中。

完整代码

将以上两个示例整合起来,我们可以实现大文件的断点续传功能。

import requests
import os

class FileUploader():
    def __init__(self, url):
        self.url = url
        self.chunk_size = 1024*1024*10

    def upload(self, file_path):
        with open(file_path, 'rb') as f:
            size = os.path.getsize(file_path)
            start = 0
            # 读取上次上传的位置
            if os.path.exists(f'{file_path}.cur'):
                with open(f'{file_path}.cur', 'r') as cf:
                    start = int(cf.read())
            f.seek(start)
            while start < size:
                end = min(start + self.chunk_size, size)
                data = f.read(self.chunk_size)
                headers = {'Content-Range': f'bytes {start}-{end-1}/{size}'}
                response = requests.put(self.url, headers=headers, data=data)
                if response.status_code == 200 or response.status_code == 201:
                    # 保存上传位置
                    with open(f'{file_path}.cur', 'w') as cf:
                        cf.write(str(end))
                    start = end
                else:
                    print(f'Error! status_code: {response.status_code}')

class FileDownloader():
    def __init__(self, url, file_path):
        self.url = url
        self.file_path = file_path
        self.chunk_size = 1024*1024*10

    def download(self):
        headers = {}
        if os.path.exists(self.file_path):
            start = os.path.getsize(self.file_path)
            headers = {'Range': f'bytes={start}-'}
            print(f'Resumable mode: start download from {start}')
        else:
            start = 0
            print('Normal mode: start download from beginning')
        response = requests.get(self.url, headers=headers, stream=True)
        with open(self.file_path, 'ab') as f:
            total_size = int(response.headers.get('content-length', start))
            for chunk in response.iter_content(chunk_size=self.chunk_size):
                if chunk:
                    f.write(chunk)
                    f.flush()
            print('Download success!')

if __name__ == '__main__':
    uploader = FileUploader('http://xxx.com/file')
    uploader.upload('bigfile.zip')

    downloader = FileDownloader('http://xxx.com/bigfile.zip', 'bigfile.zip')
    downloader.download()

结论

大文件断点续传的实现思路简单,但需要注意多线程、分块的上传下载原理以及网络请求出现错误的情况,这些都需要人为处理并产生合理的错误反馈。通过使用断点续传技术,我们可以优化文件上传和下载,增强用户体验,提升系统稳定性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python 工具类实现大文件断点续传功能详解 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • python中使用多线程改进flask案例

    下面我来为您讲解详细的“python中使用多线程改进flask案例”的完整攻略,包括两个示例说明。 什么是多线程 在计算机程序中,线程是被操作系统独立调度和分配CPU时间的基本单位。一个进程中可以包含多个线程,每个线程可以并行执行不同的任务。在Python中,可以通过使用threading模块来创建和管理线程。 为什么要使用多线程 多线程在编写Web应用程序…

    Flask 2023年5月15日
    00
  • Python实现Web服务器FastAPI的步骤详解

    下面我将为你详细讲解“Python实现Web服务器FastAPI的步骤详解”的完整攻略,包含两条示例说明。 简介 FastAPI是一个快速、现代化、Web框架,用于构建API,它是一个基于到框架运行的代码生成工具 FastAPI的Python Web框架,拥有很多现代和简单易用的特点,如自动生成API文档、类型标注和依赖注入等。本文将详细介绍如何使用Pyth…

    Flask 2023年5月16日
    00
  • jsp留言板源代码二: 给jsp初学者.

    我们来解析一下 “jsp留言板源代码二: 给jsp初学者.” 这篇文章的内容和示例。 1. 简介 该文章主要介绍了如何使用 JSP 技术开发一个简单的留言板,适合初学者练手。该留言板实现了基本的留言功能,用户可以添加留言,管理员可以浏览留言,并且可以删除不当的留言。 2. 留言板示例1 这个示例主要介绍了如何创建一个简单的留言板页面,包含了用户的留言和管理员…

    Flask 2023年5月16日
    00
  • Flask中jinja2的继承实现方法及实例

    下面是关于Flask中jinja2的继承实现方法及实例的完整攻略: 一、什么是jinja2的继承? 在Flask中使用jinja2作为模板引擎,可以方便的进行HTML页面的渲染。而模板引擎jinja2提供了模板的继承功能。它允许我们在一个基础模板中定义通用的结构和布局,然后在衍生模板中进行不同的内容扩展。 简单来说,jinja2的继承就是可以在一个基础页面中…

    Flask 2023年5月16日
    00
  • python中如何使用虚拟环境

    使用虚拟环境可以避免不同项目之间的依赖冲突,提高项目开发和部署的可靠性。下面是Python中使用虚拟环境的完整攻略: 步骤 1: 安装虚拟环境 要使用虚拟环境,我们需要先安装虚拟环境模块venv。通常情况下,Python3自带了venv模块,因此你不需要额外安装。如果你使用的是Python2,则可以使用virtualenv来创建虚拟环境。以下是在Linux或…

    Flask 2023年5月15日
    00
  • 使用Python的Flask框架实现视频的流媒体传输

    使用Python的Flask框架实现视频的流媒体传输可以分为以下步骤: 1. 安装依赖 在开始之前,请确保安装了Flask、OpenCV和FFmpeg库。 2. 准备样例视频 为了演示如何使用Flask实现视频的流媒体传输,需要一个样例视频。你可以从互联网上下载一个视频,例如https://sample-videos.com/video123/mp4/720…

    Flask 2023年5月16日
    00
  • 使用Vue.js和Flask来构建一个单页的App的示例

    下面我会详细讲解使用Vue.js和Flask来构建一个单页App的示例,包含两个示例说明。 示例1:使用Vue.js和Flask来搭建前后端分离的Todo应用 前端Vue.js 使用Vue CLI创建项目 vue create todo-vue 安装axios npm install axios 编写Todo.vue组件 <template> &…

    Flask 2023年5月16日
    00
  • 由面试题加深对Django的认识理解

    以下是“由面试题加深对Django的认识理解”的完整攻略。 第一步:准备 在开始之前,我们需要做一些准备工作。首先,我们需要了解Django的基本概念和知识点,如MVC模式、ORM、模板语言等。其次,我们需要寻找一些高质量的面试题,可以从网络上找到一些经典的面试题供我们练习。 第二步:掌握基础知识 在这一步,我们需要对Django的基础知识进行深入学习和掌握…

    Flask 2023年5月16日
    00
合作推广
合作推广
分享本页
返回顶部