浏览器文件分段断点上传简单示例(python 篇)

简介: 后端使用 Python Flask前端原理实现:1.获取文件特征码2.截取文件信息和对文件分段3.校验服务器是否存在同样特征码的没上传完的文件4.

后端使用 Python Flask

前端原理实现:

1.获取文件特征码
2.截取文件信息和对文件分段
3.校验服务器是否存在同样特征码的没上传完的文件
4.如过有同样特征码文件获取上传进度
5.否则进度从0开始
6.循环异步按顺序上传分段文件
7.如果上传完成提示成功

后端原理实现:

1.接收request(文件hash)参数
2.判断文件是否是中断上传的
3.如果存在hash文件夹获取文件夹下文件段数量返回给前端
4.不存在返回0或空字符串

5.如果前端返回上传的文件段,则保存文件段并给文件段标识索引
6.如果上传完成合并文件,删除文件段

html代码

代码以单个文件上传为例,使用hashMe.js获取特征码

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript" src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
    <script type="text/javascript" src="md5.js"></script>
    <script src="hashme.js"></script>
</head>

<body>
    <input type="file" onchange="hhh(this.files[0])" />
    <button onclick="uploadCk()">测试</button>
    <script>
        var up_f;//需要上传的信息
        var fileSplitSize = 1024 * 1024 * 2; //以2MB为一个分片
        function hhh(f) { 
            if (true) { //假设这是判断文件大小
                var hash = new hashMe(f, function(msg) {
                    up_f = new Object();
                    up_f.hash = msg;
                    up_f.name = f.name;
                    up_f.size = f.size;
                    up_f.shardCount = Math.ceil(f.size / fileSplitSize); //总片数
                    up_f.shard = [];//文件段
                    for (var i = 0; i < up_f.shardCount; i++) {
                        var start = i * fileSplitSize;
                        var end = Math.min(f.size, start + fileSplitSize);
                        up_f.shard[up_f.shard.length] = f.slice(start, end);//保存分段
                    }
                });
            }
        }

        function uploadCk() { //上传前检查 
            $.ajax({
                url: "/upload_ck",
                type: "get",
                data: {
                    hash: up_f.hash
                },
                success: function(data) {
                    if (data != "") {
                        upload(Number(data));//调用上传(索引为服务器存在的文件段索引)
                    } else { 
                        upload(0);//调用上传
                    }
                }
            });
        }

        function upload(loadIndex) { //上传
            var form = new FormData();
            form.append("hash", up_f.hash);
            form.append("name", up_f.name);
            form.append("size", up_f.size);
            form.append("shardCount", up_f.shardCount);
            form.append("blob", up_f.shard[loadIndex]);
            form.append("sdIndex", loadIndex);
            console.log("sdIndex:" + loadIndex + ",shardCount:" + up_f.shardCount)
            $.ajax({
                url: "/upload",
                type: "POST",
                data: form,
                async: true, 
                processData: false, //很重要,告诉jquery不要对form进行处理
                contentType: false, //很重要,指定为false才能形成正确的Content-Type
                success: function(data) {
                    data = Number(data) + 1;
                    if (data <= up_f.shardCount) {
                        console.log("data:" + data);
                        upload(data);
                    } else {
                        console.log("上传完毕");
                    }
                }
            });
        }
    </script>
</body>
</html>

Python代码

为示例写的Python代码有些不规范大家尽量不要模仿我这种写法(mime下载)

from flask import Flask, url_for,request 
import codecs,re,os
import urllib.parse,mime
import shutil
from werkzeug.routing import BaseConverter
class RegexConverter(BaseConverter):
    def __init__(self, map, *args):
        self.map = map
        self.regex = args[0]
        
app = Flask(__name__)
mim=mime.types
app.config['UPLOAD_FOLDER'] = 'uploads/'#保存文件位置

app.url_map.converters['regex'] = RegexConverter
@app.route('/<regex(".*"):url>')
def index(url):
    ps=urllib.parse.unquote(url)   
    if ps=="upload":
        return upload()
    elif ps.split('?')[0]=="upload_ck":
        if os.path.exists("./"+app.config['UPLOAD_FOLDER']+str(request.args.get('hash') ) ):
            return str(len( os.listdir("./"+app.config['UPLOAD_FOLDER']+str(request.args.get('hash') )) )-1 )#返回文件段索引
        else:
            return ""
    bt=codecs.open(ps,'rb',"utf-8").read() 
    return  bt, 200, {'Content-Type': mim[url.split(".")[-1]]}

@app.route('/upload', methods=['POST'])
def upload():
    hashtxt=request.form['hash']
    sPs="./"+app.config['UPLOAD_FOLDER']+hashtxt+"/"
    if not os.path.exists(sPs):#文件夹不存在
        os.makedirs(sPs)#创建hash文件夹
    uploaded_files = request.files.getlist("blob")#获取文件流集
    filePs=hashtxt+"/"+request.form['name']+".part"+request.form['sdIndex'] #文件段保存路径
    for file in uploaded_files:  
        file.save(os.path.join(app.config['UPLOAD_FOLDER'],filePs ))#保存文件
    if (int(request.form['shardCount']))==(int(request.form['sdIndex'])):#判断上传完最后一个文件
        mergeFile(app.config['UPLOAD_FOLDER'],request.form['name'],hashtxt);#合并文件
        shutil.rmtree("./"+app.config['UPLOAD_FOLDER']+hashtxt)#删除
    return request.form['sdIndex']#返回段索引
 
        
def mergeFile(ps,nm,hs):#合并文件
    temp = open(ps+"/"+nm,'wb')#创建新文件
    count=len(os.listdir(ps+"/"+hs))
    for i in range(0,count):  
        fp = open(ps+"/"+hs+"/"+nm+".part"+str(i), 'rb')#以二进制读取分割文件
        temp.write(fp.read())#写入读取数据
        fp.close()  
    temp.close()

with app.test_request_context():    #输出url
    pass
if __name__ == '__main__': 
    app.debug = True
    app.run() 
示例就这么多,但实际问题上没那么简单,比如上传校验前可以先获取服务器中已经存在的同一特征码和大小的文件,然后直接复制文件到上传的目录或提示是否覆盖等等。当然你还可以优化比如上传分段后再上传时在进行分片然后对片执行同时上传之类的。
相关文章
|
2月前
|
安全 Linux 数据安全/隐私保护
python知识点100篇系列(15)-加密python源代码为pyd文件
【10月更文挑战第5天】为了保护Python源码不被查看,可将其编译成二进制文件(Windows下为.pyd,Linux下为.so)。以Python3.8为例,通过Cython工具,先写好Python代码并加入`# cython: language_level=3`指令,安装easycython库后,使用`easycython *.py`命令编译源文件,最终生成.pyd文件供直接导入使用。
python知识点100篇系列(15)-加密python源代码为pyd文件
|
29天前
|
Web App开发 缓存 安全
WIN11 Chrome 双击打不开闪退及Chrome浏览器不能拖拽文件crx
【11月更文挑战第6天】本文介绍了 WIN11 系统中 Chrome 浏览器双击打不开闪退及不能拖拽文件 crx 的原因和解决方法。包括浏览器版本过旧、扩展程序冲突、硬件加速问题、缓存过多、安全软件冲突、系统文件损坏、用户配置文件损坏等问题的解决方案,以及 crx 文件的屏蔽、权限问题和文件格式问题的处理方法。
|
1月前
|
开发者 Python
Python中__init__.py文件的作用
`__init__.py`文件在Python包管理中扮演着重要角色,通过标识目录为包、初始化包、控制导入行为、支持递归包结构以及定义包的命名空间,`__init__.py`文件为组织和管理Python代码提供了强大支持。理解并正确使用 `__init__.py`文件,可以帮助开发者更好地组织代码,提高代码的可维护性和可读性。
31 2
|
2月前
|
Linux 区块链 Python
Python实用记录(十三):python脚本打包exe文件并运行
这篇文章介绍了如何使用PyInstaller将Python脚本打包成可执行文件(exe),并提供了详细的步骤和注意事项。
71 1
Python实用记录(十三):python脚本打包exe文件并运行
|
1月前
|
数据采集 Web App开发 JavaScript
爬虫策略规避:Python爬虫的浏览器自动化
爬虫策略规避:Python爬虫的浏览器自动化
|
1月前
|
数据挖掘 Python
Python示例,展示如何找到最近一次死叉之后尚未形成金叉的位置
金融分析中,“死叉”指短期移动平均线(如MA5)跌破长期移动平均线(如MA10),而“金叉”则相反。本文提供Python代码示例,用于找出最近一次死叉后未形成金叉的位置,涵盖移动平均线计算、交叉点判断及结果输出等步骤,适合金融数据分析。
22 1
|
2月前
|
Java Python
> python知识点100篇系列(19)-使用python下载文件的几种方式
【10月更文挑战第7天】本文介绍了使用Python下载文件的五种方法,包括使用requests、wget、线程池、urllib3和asyncio模块。每种方法适用于不同的场景,如单文件下载、多文件并发下载等,提供了丰富的选择。
|
2月前
|
数据安全/隐私保护 流计算 开发者
python知识点100篇系列(18)-解析m3u8文件的下载视频
【10月更文挑战第6天】m3u8是苹果公司推出的一种视频播放标准,采用UTF-8编码,主要用于记录视频的网络地址。HLS(Http Live Streaming)是苹果公司提出的一种基于HTTP的流媒体传输协议,通过m3u8索引文件按序访问ts文件,实现音视频播放。本文介绍了如何通过浏览器找到m3u8文件,解析m3u8文件获取ts文件地址,下载ts文件并解密(如有必要),最后使用ffmpeg合并ts文件为mp4文件。
|
2月前
|
Web App开发 SQL 数据库
使用 Python 解析火狐浏览器的 SQLite3 数据库
本文介绍如何使用 Python 解析火狐浏览器的 SQLite3 数据库,包括书签、历史记录和下载记录等。通过安装 Python 和 SQLite3,定位火狐数据库文件路径,编写 Python 脚本连接数据库并执行 SQL 查询,最终输出最近访问的网站历史记录。
36 4
|
2月前
|
JSON 数据格式 Python
Python实用记录(十四):python统计某个单词在TXT/JSON文件中出现的次数
这篇文章介绍了一个Python脚本,用于统计TXT或JSON文件中特定单词的出现次数。它包含两个函数,分别处理文本和JSON文件,并通过命令行参数接收文件路径、目标单词和文件格式。文章还提供了代码逻辑的解释和示例用法。
50 0
Python实用记录(十四):python统计某个单词在TXT/JSON文件中出现的次数