断点续传 开发中

This commit is contained in:
pixel
2020-01-21 17:17:34 +08:00
parent 4960e269c0
commit 0603010838
9 changed files with 306 additions and 14 deletions
@@ -0,0 +1,118 @@
package api
import (
"fmt"
"gin-vue-admin/controller/servers"
"gin-vue-admin/model/dbModel"
"github.com/gin-gonic/gin"
"io/ioutil"
"strconv"
)
// @Tags ExaFileUploadAndDownload
// @Summary 断点续传到服务器
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "断点续传示例"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"上传成功"}"
// @Router /fileUploadAndDownload/breakpointContinue [post]
func BreakpointContinue(c *gin.Context) {
fileMd5 := c.Request.FormValue("fileMd5")
fileName := c.Request.FormValue("fileName")
chunkMd5 := c.Request.FormValue("chunkMd5")
chunkNumber, _ := strconv.Atoi(c.Request.FormValue("chunkNumber"))
chunkTotal, _ := strconv.Atoi(c.Request.FormValue("chunkTotal"))
_, FileHeader, err := c.Request.FormFile("file")
if err != nil {
servers.ReportFormat(c, false, fmt.Sprintf("%v", err), gin.H{})
} else {
f, err := FileHeader.Open()
if err != nil {
servers.ReportFormat(c, false, fmt.Sprintf("%v", err), gin.H{})
} else {
cen, _ := ioutil.ReadAll(f)
defer f.Close()
if flag := servers.CheckMd5(cen, chunkMd5); flag {
err, file := new(dbModel.ExaFile).FindOrCreateFile(fileMd5, fileName, chunkTotal)
if err != nil {
servers.ReportFormat(c, false, fmt.Sprintf("%v", err), gin.H{})
} else {
err, pathc := servers.BreakPointContinue(cen, fileName, chunkNumber, chunkTotal, fileMd5)
if err != nil {
servers.ReportFormat(c, false, fmt.Sprintf("%v", err), gin.H{})
} else {
err = file.CreateFileChunk(pathc, chunkNumber)
if err != nil {
servers.ReportFormat(c, false, fmt.Sprintf("%v", err), gin.H{})
} else {
servers.ReportFormat(c, true, "切片创建成功", gin.H{})
}
}
}
} else {
}
}
}
}
// @Tags ExaFileUploadAndDownload
// @Summary 查找文件
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file params file true "查找文件"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查找成功"}"
// @Router /fileUploadAndDownload/findFile [post]
func FindFile(c *gin.Context) {
fileMd5 := c.Query("fileMd5")
fileName := c.Query("fileName")
chunkTotal, _ := strconv.Atoi(c.Query("chunkTotal"))
err, file := new(dbModel.ExaFile).FindOrCreateFile(fileMd5, fileName, chunkTotal)
if err != nil {
servers.ReportFormat(c, false, fmt.Sprintf("查找失败:%v", err), gin.H{})
} else {
servers.ReportFormat(c, true, "查找成功", gin.H{"file": file})
}
}
// @Tags ExaFileUploadAndDownload
// @Summary 查找文件
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file params file true "查找文件"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查找成功"}"
// @Router /fileUploadAndDownload/findFile [post]
func BreakpointContinueFinish(c *gin.Context) {
fileMd5 := c.Query("fileMd5")
fileName := c.Query("fileName")
err, filePath := servers.MakeFile(fileName, fileMd5)
if err != nil {
servers.ReportFormat(c, true, fmt.Sprintf("文件创建失败:%v", err), gin.H{})
} else {
servers.ReportFormat(c, true, "文件创建成功", gin.H{"filePath": filePath})
}
}
// @Tags ExaFileUploadAndDownload
// @Summary 删除切片
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file params file true "查找文件"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查找成功"}"
// @Router /fileUploadAndDownload/removeChunk [post]
func RemoveChunk(c *gin.Context) {
fileMd5 := c.Query("fileMd5")
fileName := c.Query("fileName")
filePath := c.Query("filePath")
err := servers.RemoveChunk(fileMd5)
err = new(dbModel.ExaFile).DeleteFileChunk(fileMd5, fileName, filePath)
if err != nil {
servers.ReportFormat(c, true, fmt.Sprintf("缓存切片删除失败:%v", err), gin.H{})
} else {
servers.ReportFormat(c, true, "缓存切片删除成功", gin.H{})
}
}
@@ -0,0 +1,75 @@
package servers
import (
"gin-vue-admin/tools"
"io/ioutil"
"os"
"strconv"
)
// 前端传来文件片与当前片为什么文件的第几片
// 后端拿到以后比较次分片是否上传 或者是否为不完全片
// 前端发送每片多大
// 前端告知是否为最后一片且是否完成
const breakpointDir = "./breakpointDir/"
const finishDir = "./fileDir/"
func BreakPointContinue(content []byte, fileName string, contentNumber int, contentTotal int, fileMd5 string) (error, string) {
path := breakpointDir + fileMd5 + "/"
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
return err, path
}
err, pathc := makeFileContent(content, fileName, path, contentNumber)
return err, pathc
}
func CheckMd5(content []byte, chunkMd5 string) (CanUpload bool) {
fileMd5 := tools.MD5V(content)
if fileMd5 == chunkMd5 {
return true // "可以继续上传"
} else {
return false // "切片不完整,废弃"
}
}
func makeFileContent(content []byte, fileName string, FileDir string, contentNumber int) (error, string) {
path := FileDir + fileName + "_" + strconv.Itoa(contentNumber)
f, err := os.Create(path)
defer f.Close()
if err != nil {
return err, path
} else {
_, err = f.Write(content)
if err != nil {
return err, path
}
}
return nil, path
}
func MakeFile(fileName string, FileMd5 string) (error, string) {
rd, err := ioutil.ReadDir(breakpointDir + FileMd5)
if err != nil {
return err, finishDir + fileName
}
_ = os.MkdirAll(finishDir, os.ModePerm)
fd, _ := os.OpenFile(finishDir+fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
for k, _ := range rd {
content, _ := ioutil.ReadFile(breakpointDir + FileMd5 + "/" + fileName + "_" + strconv.Itoa(k))
_, err = fd.Write(content)
if err != nil {
_ = os.Remove(finishDir + fileName)
return err, finishDir + fileName
}
}
defer fd.Close()
return nil, finishDir + fileName
}
func RemoveChunk(FileMd5 string) error {
err := os.RemoveAll(breakpointDir + FileMd5)
return err
}