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值是在選擇文件之後調用一個方法來生成的。

後端

主要思路如下:

  • 先保存當前分片到臨時文件夾
  • 維護一個全局的集合用來判斷當前是否是最後一個分片
  • 如果是最後一個分片,則 開始合併臨時文件夾裏的文件到一個流中
  • 將這個合併後的數據流輸出到一個新的文件中
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章