• 文件分片上传和断点续传



    今天面试的时候,说到大文件上传这里,面试官大佬问了分片上传,但是我只知道一些浅薄的分片上传。🆗现在来详细学一下上传方式吧!

    为什么大文件要分片上传呢?

    是因为文件一旦过大,如果仅当成一次请求发送的话,这个请求的时间就会非常的长,一旦请求的过程中出现一些问题,比方说网络断开了,那么就不得不把整个文件重新上传一遍,那这样代价就太大了, 也非常浪费资源,所以说我们在做大文件上传的时候往往会对文件进行分片。

    整个过程

    就是在客户端这边,首先把整个的大文件数据分成一个一个的数据小块,可以把每一块想象成一个单独的小文件,然后利用单文件上传,把这些小文件以此上传到服务器,当最后把文件全部传输完成之后,在服务器端使用程序把整个文件的小数据组装起来(后端负责的),形成一个完整的文件。

    分片上传很快,瞬间就可以完成。

    无论是file文件还是Blob文件,里面其实只是保存了文件的基本信息,比方说,file保存了文件的大小(size),文件的类型(type),文件的名字(name),位置这些基本信息,并没有保存文件的数据,Blob保存了文件的大小和类型,所以我们对文件进行分片其实就是一个简单的数据运算而已,如果说我们将来需要读取他的数据的时候,需要用到FileReader,才能真正的把数据去读取出来,这就是说分片的数据为什么是非常非常快的。

    OK,我们大文件上传光有分片就完事儿了吗?

    假设我们上传分片,上传到一半的时候,断网了,要接着上传,那之前上传的分片肯定就不用上传了,这就属于文件秒传。
    OK,现在来看一下基本原理:
    就是跟服务器的一次对话,比方说我现在刷新了页面,我要重新上传这个文件,我就问一下服务器,“我要给你上传一个文件,这个文件呢,你告诉我是什么情况,我上传过了没有啊还有哪些分片没有上传”服务器一看,🆗这些呢之前已经上传过这些分片了,那我就告诉了还有哪些编号的分片你还需要传递给我,通过一个ajax请求,客户端就知道接下来文件该怎么处理,在交互过程中,客户端必须告诉服务器一个关键的信息,
    那什么叫 “ 这个文件呢?”
    需要用一个东西来描述这个文件,那怎么来描述这个文件呢,首先肯定不能使用文件名,因为文件名容易重复,用路径也不行,因为路径会变化,所以需要找一个唯一的能代表这个文件的东西,就是文件hash,

    哈希是一种算法,它可以把任何数据,不管是二进制也好还是一个字符串也好,换算成一个固定长度的字符串,这个换算是单向的,就是从数据到这个hash值,他是不可逆的,也就是说不能通过字符串反向推导出数据是啥,这有什么意义呢?哈希还有个特点,它对数据变化非常敏感,哪怕两个数据里面只换算了一个字节,那整个换算结果就完全不一样了,那么也就意味着,我们可以利用这个hash值,来代表文件的整个数据

    上传的时候告诉你,我现在上传的文件的hash值是啥,服务器你记录一下,下一次我再重传的时候,我再告诉你,你看一下这个hash值之前 有没有传过,还有哪些分片还要上传。

    通过hash值就能代表整个文件的内容,从数据到hash值的过程称之为hash算法,hash算法有很多,我们常用的是md5,关键点来了
    我们如何在客户端计算出这个文件的hash值?
    嘿嘿不知道算法的可以使用第三方库(反正我不知道)
    spark-md5可以npm安装,也可以页面上script标签引入.

    代码实现:

    <input type="file"/>
    <script src="这里引入一下spark-md5.js路径,我可以假装在这里引入了,你可以假装看见"></script>
    <script>
    const inp=document.querySelector('input');
    inp.onchange= async(e)=>{
    	const file = inp.files[0];
    	if(!file){
    	return;
    	}
    	const chunks=createChunks(file,10*1024*1024);
    	//调用一下
    	coust result=await hash(chunks);
    	console.log(result);
    	//const piece=file.slice(0,100);//取0~99个数据
    	//console.log(piece);//Blob类型,也是表示文件数据的,
    	//也就是说用ajax请求的时候可以直接把这个东西发到服务器,它的用法跟file对象的用法是一样的
    }
    
    //引入spark-md5之后要做的事情不推荐一次性计算整个文件的hash,因为要计算hash值必须拿到文件的数据,
    //全部拿到要是这个文件数据很大多费劲啊,把这些数据全部读取到内存里面然后去计算hash值,内存吃不消啊,
    //所以我们的hash要用分快去算,这里叫做增量算法 (就是先用其中一块数据计算出一个结果,然后计算过后这块数据就不要了,接下来就是下一个数据来了,再跟之前的结果一起计算一个新的结果,然后不要酱紫内存就不会撑爆,)
    function hash(chunks){ 
    // 因为需要时间 所以封装一个异步函数
    return new Promise(resolve=>{
    
    //写一个递归的函数,读取第几个分快
    	function _read(i){
    	//终止条件
    	if(i>=chunks.length){
    	//告诉它完事儿了得到一个hash
    	reso(spark.end())
    	return;//读完了呗
    	}
    	const blob=chunks[i];
    	const reader = new FileReader();
    	//读取的过程是异步的,所以有个方法叫onload
    	reader.onload = e =>{
    		const bytes=e.target.result//读取到字节数组,并使用增量hash进行计算用第三方库
    		//吧一组字节加到这个运算当中
    		spark.append(bytes);
    		//加入下一个分片
    		_read(i+1);
    	}
    	//读取它的字节数
    	reader.readAsArrayBuffer(blob);
    	}
    	_read(0)
    })
    
    }
    function creatChunks(file,chunkSize){//写个工具函数,传递一个file对象,然后再传进来一个每个切片的大小,
    //单位是字节,来完成切片
    //先创建好一个数组来获取每一个切片
    	const result=[];
    //然后就使用循环了,每取完一次,往前跳进一个切片的长度
    	for(let i=0;i<file.size;i+=chunkSize){
    	
    	//把每次切片的结果放到result数组里面取
    		result.push(file.slice(i,i+chunkSize);)
    	}
    		return result;
    	}
    
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    在实际开发中,运算过程一般是不会放到主线程里面的,运算时间比较长,我们可以利用web worker单独开一个线程去处理这个事情,这样避免浏览器卡死。

    但是如果放到单独的线程里面去还是可能会导致卡顿,因为他是一个CPU特别密集的任务,所以很多b站抖音很多站点还当发现文件特别大的时候,先粗略对文件分成一个大块,单独去计算每个大块,这样计算起来就非常快了,先计算大块,当空闲的时候再计算大块里面的hash值。

  • 相关阅读:
    vscode登录同步打开vscode.dev失败解决方法
    IS ATTENTION BETTER THAN MATRIX DECOMPOSITION
    【数据库】实验一 openGauss数据库管理系统
    ARM 和 龙芯上 Arch Linux 安装手记
    关于Java NIO的的思考
    LeetCode 1779. 找到最近的有相同 X 或 Y 坐标的点
    GsonUtils和字符串
    Dos常用命令符
    Windows10专业版系统安装Hyper-V虚拟机软件
    《操作系统真象还原》第一章 部署工作环境
  • 原文地址:https://blog.csdn.net/qq_60893085/article/details/133890095