断点续传

前言

我们每个人应该都使用过专门的下载工具,像迅雷、QQ旋风、百度网盘等。我们在下载或上传文件的时候,有时候可能由于网络的原因,还没下载完毕或者上传完毕,比如我现在使用迅雷下载一个文件,下载到了80%的时候断网了,我把电脑关了,等到有网络的时候,又打开电脑,打开迅雷,继续下载,这时并不是从头开始下载,而是从80%的时候继续下载,一直到下载完毕。实际上这就是一个断点续传的场景。

断点续传

通常视频文件都比较大,所以对于上传文件的需求要满足大文件的上传要求。http协议本身对上传文件大小没有限制,但是客户的网络环境质量、电脑硬件环境等参差不齐,如果一个大文件还没上传完毕而网断了,电断了,没有上传完成,需要客户重新上传,这是致命的,所以对于大文件上传的要求最基本的是断点续传。

1、概念

FTP(文件传输协议的简称)(File Transfer Protocol、 FTP)客户端软件断点续传指的是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没有必要从头开始上传下载。用户可以节省时间,提高速度。

小结:断点续传的关键是对资源进行分块,然后对块文件进行上传或下载。

2、上传或下载流程

以下对上传流程进行说明,下载类似:
在这里插入图片描述
说明:

  • 上传前先把文件分成块。
  • 一块一块的上传,上传中断后重新上传,已上传的分块则不用再上传。
  • 各分块上传完成最后合并文件。

3、文件的分块和合并

为了更好的理解文件分块上传的原理,下边用java代码测试文件的分块与合并。

(1)文件分块

分块流程如下:

  • 获取源文件长度。
  • 根据设定的分块文件的大小计算出块数。
  • 从源文件读数据依次向每一个块文件写数据。

下面用代码实现视频文件的分块:

public class Test {

    // 测试文件的分块
    public static void main(String[] args) throws IOException {
        // 源文件对象
        File file = new File("E:/ffmpeg/无上神帝01.mp4");
        // 块文件目录
        String chunkFolder = "E:/ffmpeg/chunk/";
        File file2 = new File(chunkFolder);
        if (!file2.exists()) {
            file2.mkdirs();
        }
        // 定义每个块文件的大小,这里规定为1M
        long chunkSize = 1 * 1024 * 1024;
        // 源文件的大小
        double fileSize = file.length() * 1.0;
        // 计算块数,向上取整
        long chunkNum = (long) Math.ceil(fileSize / chunkSize);
        // 创建文件读取对象
        RandomAccessFile raf_read = new RandomAccessFile(file, "r");
        // 缓冲区
        byte[] bys = new byte[1024];
        System.out.println("开始分块......");
        for (int i = 0; i < chunkNum; i++) {
            // 块文件对象
            File chunkFile = new File(chunkFolder + i);
            // 块文件的写对象
            RandomAccessFile raf_write = new RandomAccessFile(chunkFile, "rw");
            int len = -1;
            while ((len = raf_read.read(bys)) != -1) {// 读取
                // 写入
                raf_write.write(bys, 0, len);
                // 达到1M时开始写下一块
                if (chunkFile.length() >= chunkSize) {
                    break;
                }
            }
            // 每个写入对象都需要关闭
            raf_write.close();
        }
        // 全部读写完毕后,关闭读对写
        raf_read.close();
        System.out.println("源文件已分块完毕,请查看!");
    }

}

执行,控制台:
在这里插入图片描述
查看:
在这里插入图片描述
在这里插入图片描述
一共是分了56块,除了最后一块,每一块的大小都是1M。分完块之后,可以对每一块进行上传并且记录位置,这样即使没有上传完毕,下载可以接着断开的地方继续上传,而不必从头开始传。

(2)文件合并

合并流程如下:

  • 找到要合并的文件并按文件合并的先后进行排序。
  • 创建合并文件。
  • 依次从合并的文件中读取数据向合并文件写入数据。
  • 删除块文件。

以下为代码:

public class Test {

    // 测试块文件的合并
    public static void main(String[] args) throws IOException {
        // 块文件所在目录
        String chunkFolder = "E:/ffmpeg/chunk/";
        // 文件对象
        File file = new File(chunkFolder);
        // 获取目录列表
        File[] files = file.listFiles();
        // 数组转集合
        List<Object> list = Arrays.asList(files);
        // 块文件按名称排序
        Collections.sort(list, new Comparator<Object>() {

            // 排序规则为按名称升序
            @Override
            public int compare(Object o1, Object o2) {
                // 类型转换
                File f1 = (File) o1;
                File f2 = (File) o2;
                if (Integer.parseInt(f1.getName()) > Integer.parseInt(f2.getName())) {
                    return 1;
                }
                return -1;
            }
        });

        // 合并后的文件对象
        File mergeFile = new File("E:/ffmpeg/合并文件.mp4");
        // 创建对象
        mergeFile.createNewFile();
        // 写对象
        RandomAccessFile raf_write = new RandomAccessFile(mergeFile, "rw");
        byte[] bys = new byte[1024];
        System.out.println("开始合并块文件......");
        for (Object obj : list) {
            File chunkFile = (File) obj;
            // 读对象
            RandomAccessFile raf_read = new RandomAccessFile(chunkFile, "r");
            int len = -1;
            while ((len = raf_read.read(bys)) != -1) {
                raf_write.write(bys, 0, len);
            }
            // 每个读对写都需要关闭
            raf_read.close();
        }
        // 全部读写完毕后关闭写对象
        raf_write.close();
        // 将块文件全部删除
        for (File f : files) {
            f.delete();
        }
        // 目录删除
        file.delete();
        System.out.println("块文件合并完成,请查看!");
    }

}

执行,控制台:
在这里插入图片描述
查看:
在这里插入图片描述
原来的chunk目录已经删除了,而且生成了合并文件,打开文件看是否能播放:
在这里插入图片描述
可以播放,没问题。全部分块上传完毕后,可以合并分块小文件为一个大文件,然后删除掉块文件。

4、总结

断点续传在大文件的上传和下载中尤为常见,理解断点续传的工作原理,并掌握分块和合并,提升用户的上传、下载体验。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flask是一个基于Python的轻量级Web应用框架,它提供了一种简单而灵活的方式来构建Web应用程序。断点是指在文件上或下载过程中,如果中断了连接或者出现其他异常情况,可以从中断的位置继输而不需要重新开始。 在Flask中实现断点可以通过以下步骤: 1. 在Flask应用中配置文件上的最大大小,可以使用`app.config['MAX_CONTENT_LENGTH']`来设置最大文件大小。 2. 在前端页面中使用HTML的`<input type="file">`标签来实现文件上功能。 3. 在后端的路由函数中,使用`request.files`获取上的文件对象。 4. 判断是否存在已上的部分文件,可以通过检查请求头中的`Range`字段来判断是否有断点的需求。 5. 如果有断点的需求,可以通过读取已上的部分文件,然后在继时将数据追加到已上的文件中。 6. 如果没有断点的需求,直接保存上的文件即可。 下面是一个简单的示例代码: ```python from flask import Flask, request app = Flask(__name__) @app.route('/upload', methods=['POST']) def upload(): file = request.files['file'] if 'Range' in request.headers: # 断点逻辑 range_header = request.headers['Range'] # 解析Range字段,获取已上的文件大小 # 根据已上的文件大小,将数据追加到已上的文件中 else: # 直接保存上的文件 file.save('path/to/save/file') return 'Upload success' if __name__ == '__main__': app.run() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值