美文网首页
大文件断点续传

大文件断点续传

作者: Shiki_思清 | 来源:发表于2020-12-01 18:19 被阅读0次

    spark-MD5 增量计算切片

    npm i spark-md5
    https://github.com/satazor/js-spark-md5

    1. 做切片 blob.slice()

    2. 使用webworker来做多线程,需要把文件单独放在public下,可供直接访问

    3. var worker = new Worker('work.js');

    4. 使用requestIdleCallback ,deadline.timeRemaining() > 1 是否空闲

    1. 算MD5 重新计算对象,拆成n个新的对象{ chunk, name, hash}, 分别发起后台请求

    2. 后台拿到碎片之后,存到文件夹中 名字为
      [
      hash-1,
      hash-2,
      hash-3,
      ...
      ]

    3. 先执行check请求,拿到已经上传是成功的list , 过滤,如果成功的,就不再上传

    4. 前台发起合并请求,拿到后缀ext,大小size, hash,

    5. 后台通过pipe来读取流文件,并合并成一个新文件。
      合并前需要根据 123来进行sort重拍

    断点续传

    1. 前台发送一个check 请求,判断是否合并的文件是否存在,如果不存在则表示合并失败了,再判断是否存在文件夹,再查看文件夹里缺哪个块
      请求数据参数为 ext,hash
    2. 后台拿到参数后判断,{hash}.{ext} 是否存在 如果存在,返回uploaded=true
      如果不存在,判断文件夹是否存在,不存在 返回 uploaded=false,uploadlist=[]
      如果存在,读取文件,需要过滤隐藏文件,name[0]!='.' ,返回uploaded=false,uploadlist
    method: {
      createFileChunk(file, size=1*1024*1024) {
        const chunks = [];
        let cur = 0;
        while(cur < this.file.size) {
          chunks.push({index: cur, file: this.file.slice(cur, cur+size)});
          cur+=size
        }
        return chunks 
      },
      calculateHashIdle () {
         const spark = new self.SparkMD5.ArrayBuffer()
    
         let progress = 0
         let count  = 0
    
        const workLoop = async deadline
    
      },
      calculateHashWorker () {
        return new Promise(resolve => {
          this.worker = new Worker('/hash.js')  // 新建一个work线程
          this.worker.postMessage({chunks: this.chunks})
          this.worker.onmessage = e => {
            const {progress, hash = e.data}  //  拿到进度和hash
            this.hashProgress = Number(propgress.toFixed(2))
            if (hash ) {  // 当hash 有值,则表示已经有结果,返回这个hash值
              resolve(hash)
             }
          }
        })
      },
      calculateHashIdle () {
        const workloop= async deadline => {
          while(count<chunks.length && deadline.timeRemaining() > 1) {
            // 空闲,且转MD5任务还没执行完
            // 执行分片
          }
          window.requestIdleCallback(workloop)
        }
        window.requestIdleCallback(workloop)
      },
      async unloadFile() {
        if (!this.isImage(this.file))  {
          console.log("不合规则")
          return
        }
        const chunks = this.createFileChunk(this.file)
        const hash = await this.calculateHashWorker()
    
        // 进行上传
    
        this.chunks = chunks.map((chunk, index) => {
          const form = new FormData()
           form.append('chunk', chunk.chunk),
          form.append('hash', chunk.hash),
          form.append('name', chunk.name + index)
          return form
        }).map((form, index) => this.$http.post('/uploadfile', {
          // 对每个切片进行分开上传
          onUploadProgress: progress => {
    
           }
        }))
    
    
        /**   不能再直接拼成formData上传了
        const form = new FormDate();
        form.append('name', 'file'); 
        form.append('file', this.file);
        const ret = await this.$http.post('/upoadfile', form, {
            onUploadProgress: progress => {
              this.uploadProgress = Number(((progress.loaded / progress.total)*100).toFixed(e))
            }
         })
        */
      }
    }
    
    // hash.js
    // 引入spark-md5  
    /**
    Worker 线程有一些自己的全局属性和方法。
    
    self.name: Worker 的名字。该属性只读,由构造函数指定。
    self.onmessage:指定message事件的监听函数。
    self.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。
    self.close():关闭 Worker 线程。
    self.postMessage():向产生这个 Worker 线程发送消息。
    self.importScripts():加载 JS 脚本。
    */
    
    self.importScripts('spak0md5.min.js')
    
    self.onmessage = e => {
      const {chunk} = e.data
      // self代表子线程自身,即子线程的全局对象。
      const spark = new self.SparkMD5.ArrayBuffer()
    
      let progress = 0
      let count  = 0
    
      const loadNext = index => {
        const reader = new FileReader()
        reader.readAsArrayBuffer(chunks[index].file)  // 会将文件内容读取为ArrayBuffer对象
        reader.onload = e => {  // 当读取操作成功完成时调用
          count ++
          spark.append(e.target.result)
          if () {
            self.postMessage({progress: 100, hash: spak.end()})
           } else {
            progress += 100/chunks.length
            self.postMessage({
              progress
            })
            loadNext (count)
          }
        }
      }
    }
    
    
    
    

    相关文章

      网友评论

          本文标题:大文件断点续传

          本文链接:https://www.haomeiwen.com/subject/zmeswktx.html