Java-断点续传 【文件分块】

什么是断点续传?

引用百度百科:对断点续传的定义

个人理解:如果我们要在项目的媒资管理部分,上传视频文件(通常这类视频文件都比较大),http协议本身对上传文件大小没有限制,但是客户的网络环境质量,电脑硬件环境参差不齐,可能会导致一个大文件快上传完了出现断网的情况,从而导致文件没有上传成功,需要客户重新上传,用户体验非常差,所以对于大文件上传的要求是能做到 断点续传

断点续传流程图如下图:

简要概述实现步骤:

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

(为了方便理解,我用Java代码的方法 测试文件的分块与合并)

先进行大文件资源 分块操作:

1.导入一系列的包

package com.xuecheng.media;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.*;

导入多个外部和Java自带的库,其中org.apache.commons.codec.digest.DigestUtils:用于生成文章的摘要,能够在断点续传中验证文件的完整性

2.定义相关的类和方法

public class BigFileTest {
    //测试文件分块方法
    @Test
    public void testChunk() throws IOException {

定义一个公共类BigFileTest,用于包含文件处理相关的测试方法,并且定义了一个testChunk方法,该方法用于执行文件分块操作,并声明了可能抛出IOException异常,因为文件操作可能会失败

3.创建分块文件

File sourceFile = new File("d:/develop/bigfile_test/nacos.mp4");
String chunkPath = "d:/develop/bigfile_test/chunk/";
File chunkFolder = new File(chunkPath);
if (!chunkFolder.exists()) {
    chunkFolder.mkdirs();
}

创建一个File对象,表示要对d:/develop/bigfile_test/路径下的nacos.mp4源文件进行分块,并创建一个File对象,表示分块存储的文件夹,如果分块文件夹不存在,则创建它

 4.对大文件分成文件块

//分块大小
long chunkSize = 1024 * 1024 * 1;
//分块数量
long chunkNum = (long) Math.ceil(sourceFile.length() * 1.0 / chunkSize);
System.out.println("分块总数:" + chunkNum);

然后对 文件进行分割,定义每个分块的大小,通过源文件的长度除以分块大小(要采用向上取整噢)使用Math.ceil方法向上取整,计算出分块的总数

5.进行对文件的读取写入

//缓冲区大小
byte[] b = new byte[1024];
//使用RandomAccessFile访问文件
RandomAccessFile raf_read = new RandomAccessFile(sourceFile, "r");
//分块
for (int i = 0; i < chunkNum; i++) {
    //创建分块文件
    File file = new File(chunkPath + i);
    if (file.exists()) {
        file.delete();
    }
    boolean newFile = file.createNewFile();
    if (newFile) {
        //向分块文件中写数据
        RandomAccessFile raf_write = new RandomAccessFile(file, "rw");
        int len = -1;
        while ((len = raf_read.read(b))!= -1) {
            raf_write.write(b, 0, len);
            if (file.length() >= chunkSize) {
                break;
            }
        }
        raf_write.close();
        System.out.println("完成分块" + i);
    }
}
raf_read.close();

然后进行缓冲区与文件读取写入,以上代码块创建了一个大小为1024字节的缓冲区数组b,用于读取源文件数据,并且以只读模式打开源文件,然后进行分块操作

循环分块数量chunkNum(对源文件进行分块后得到的分块总数),if循环判断分块文件是否创建成功,如果创建成功,则从源文件中读取数据到缓冲区,直到读取到文件末尾

再进行分块文件 合并操作:

各个文件块读取完毕后,就可以进行 文件合并 操作,分块合并步骤

File chunkFolder = new File("D:\\...\\chunk\\");  // 分块文件目录
File sourceFile = new File("D:\\...\\星际牛仔1.mp4");  // 原始文件
File mergeFile = new File("D:\\...\\星际牛仔1-1.mp4");  // 合并后的文件
mergeFile.createNewFile();  // 创建空的目标文件

定义分块文件的存储目录,原始文件路径和合并后的文件路径,并创建一个空的目标文件

RandomAccessFile raf_write = new RandomAccessFile(mergeFile, "rw");  // 以读写模式打开合并文件
byte[] buffer = new byte[1024];  // 读写缓冲区(1KB)

初始化写入流,RandomAccessFile是一个用于随机访问文件的类,适合大文件操作,“rw”表示读写模式,byte[ ] buffer = new byte[1024]这段代码创建了一个字节数组,作为读写缓冲区(临时存储从文件或网络中读取的数据),每次读取1KB数据,减少磁盘I/O次数

//listFiles()表示返回目录中所有文件和子目录的File数组,files是包含所有分块文件的数组
File[] files = chunkFolder.listFiles();
//将数组转换为list集合,fileList是包含所以分块文件的list<File>
List<File> fileList = Arrays.asList(files);
//然后对List进行排序,Comparator.comparingInt创建一个比较器,按照指定规则排序(将文件名转换为整数进行排序)
Collections.sort(fileList, Comparator.comparingInt(o -> Integer.parseInt(o.getName())));

对分块文件进行排序,o -> Integer.parseInt(o.getName()):是一个Lambda表达式,用于将文件名转换为整数进行排序

//循环遍历分块文件列表
for (File chunkFile : fileList) {
//以只读模式打开分块文件 "r"表示以只读模式打开
    RandomAccessFile raf_read = new RandomAccessFile(chunkFile, "r"); 
//读取分块文件内容并写入合并文件
    int len;
    while ((len = raf_read.read(buffer)) != -1) {  
        raf_write.write(buffer, 0, len);  
    }
    raf_read.close();  // 关闭分块文件流
}
raf_write.close();  // 关闭合并文件流

这段代码遍历分块文件列表,并以只读模式打开分块文件,然后读取分块文件内容并写入到合并文件,最后关闭分块文件流和合并文件流

这里我再总结一下掌握断点续传的技术,我们能够将多个分块文件合并成一个完整文件,避免用户在下载过程因为网络,系统等一系列原因导致下载中断,而需重新开始下载的情况。而是可以直接从中断处继续下载,节省了我们时间和网络资源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值