java断点续传

前言

断点续传就是从文件上次中断的地方开始重新下载或上传,当下载或上传文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会去重头下载,这样很浪费时间。并且对于大型文件,采用切片上传的方法,客户端对文件进行切片处理后,多次请求服务器,每次只传递一个分片。

前端

前端需要对上传的文件进行分片处理,记录当前上传的文件分片的开始字节start和结束字节end,同时,整个大文件有一个md5值作为文件的唯一标识,避免重复上传。每次请求服务器传递的分片即是startend的部分文件内容。
文件切片及上传分片的代码:
这里upload是一个递归的函数

 // 确认上传
    handleUpload() {
      if (!this.previewResource) {
        this.$message.warning('请先选择需要上传的资源!')
        return
      }
      // 先判断选中的资源是否已经上传过
      const data = { md5value: this.resourceForm.md5value }
      this.$api.isResourceFileExist(data).then(response => {
        if (response.data.exist) {
          // 文件已经上传
          this.uploadExistFile()
        } else {
          // 文件还未上传
          this.splitFile()
        }
      })
    },
    // 文件已经上传,不需要再上传文件
    uploadExistFile() {
      let data = new FormData()
      data.append('knowCateIds', this.resourceForm.knowCateIds)
      data.append('title', this.resourceForm.title)
      data.append('resourceType', this.resourceForm.resourceType)
      data.append('brief', this.resourceForm.brief)
      data.append('md5value', this.resourceForm.md5value)
      data.append('name', this.resourceForm.name)
      data.append('iconMd5value', this.resourceForm.iconMd5value)
      this.$api
        .uploadResource(data)
        .then(_ => {
          this.$message.success('资源上传成功!')
          this.goback()
        })
        .catch(_ => {
          this.$message.error('资源上传失败!')
        })
    },
   // 文件切片
    splitFile() {
      // 初始化切片
      let file = this.previewResource // 需要分片上传的文件
      let splitSize = 5 * 1024 * 1024 // 每片文件的大小(5M)
      let size = file.size // 文件的总大小
      let start = 0 // 分片开始上传时的大小
      let end // 分片结束上传时的大小
      let index = 1 // 分片序号
      let totalPieces = Math.ceil(size / splitSize) // 总分片数
      // 初始化进度条
      this.uploadProgress = 0
      this.uploadDialogVisible = true
      this.upload(start, end, index, splitSize, size, file, totalPieces)
    },
    // 开始上传
    upload(start, end, index, splitSize, size, file, totalPieces) {
      if (start < size) {
        end = start + splitSize
        if (end > size) {
          end = size
        }
        let chunk = file.slice(start, end)
        let data = new FormData()
        Object.keys(this.resourceForm).forEach(key => {
          data.append(key, this.resourceForm[key])
        })
        data.append('file', chunk)
        data.append('chunks', totalPieces)
        data.append('chunk', index)
        this.$api
          .uploadResource(data)
          .then(response => {
            this.uploadProgress = Math.round(index / totalPieces * 100)
            start = end
            index++
            if (index > totalPieces) {
              this.$message.success('资源上传成功!')
              this.uploadDialogVisible = false
            }
            this.upload(start, end, index, splitSize, size, file, totalPieces)
          })
          .catch(_ => {
            this.$message.error('资源上传失败!')
            this.uploadDialogVisible = false
          })
      }
    }
    

md5值是在选择文件之后调用一个方法来生成的。

后端

主要思路如下:

  • 先保存当前分片到临时文件夹
  • 维护一个全局的集合用来判断当前是否是最后一个分片
  • 如果是最后一个分片,则 开始合并临时文件夹里的文件到一个流中
  • 将这个合并后的数据流输出到一个新的文件中

你可能感兴趣的:(Java后台)