2023-04-29 Go基础——gin

2024-03-06  本文已影响0人  Lovevivi

用gin框架写一个大文件分块传输的完整代码

这里是一个使用gin框架实现的大文件分块传输的示例代码:

package main

import (
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
    "strconv"

    "github.com/gin-gonic/gin"
)

// 文件块大小,每块10M
const blockSize = 10 * 1024 * 1024

// 上传的文件对象
type File struct {
    Name     string
    File     *os.File
    FileSize int64
    Blocks   int64
    Done     bool
}

// gin路由,所有请求都由此处理
func uploadFile(c *gin.Context) {
    // 获取请求的参数
    name := c.PostForm("name")
    file, _ := c.FormFile("file")
    size := file.Size

    // 打开文件,准备上传
    f, err := file.Open()
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    saveFile, err := os.Create(file.Filename)
    if err != nil {
        log.Fatal(err)
    }
    defer saveFile.Close()

    // 创建文件对象
    uploadFile := &File{
        Name:     name,
        File:     saveFile,
        FileSize: size,
        Blocks:   size / blockSize,
        Done:     false,
    }

    // 如果有上次未完成的上传,续传
    blockStart := c.PostForm("blockStart")
    blockEnd := c.PostForm("blockEnd")
    if blockStart != "" {
        start, _ := strconv.Atoi(blockStart)
        end, _ := strconv.Atoi(blockEnd)
        _, err = uploadFile.File.Seek(int64(start), 0)
        if err != nil {
            log.Fatal(err)
        }
        for i := start; i <= end; i++ {
            uploadFile.Done = uploadBlock(f, uploadFile, i) == nil
        }
    }

    // 如果不是续传,开始分块上传
    if !uploadFile.Done {
        for i := 0; i < int(uploadFile.Blocks); i++ {
            err = uploadBlock(f, uploadFile, i)
            if err != nil {
                c.String(http.StatusBadRequest, fmt.Sprintf("upload block %d failed", i))
                return
            }
        }
    }
    
    // 上传完成,返回成功
    c.String(http.StatusOK, "file upload success")
}

// 上传单个文件块
func uploadBlock(file *os.File, uploadFile *File, blockNum int) error {
    start := blockSize * blockNum
    end := start + blockSize - 1
    if end > uploadFile.FileSize - 1 {
        end = uploadFile.FileSize - 1
    }

    buf := make([]byte, blockSize)
    _, err := file.ReadAt(buf, int64(start))
    if err != nil && err != io.EOF {
        return err
    }

    _, err = uploadFile.File.WriteAt(buf, int64(start))
    if err != nil {
        return err
    }

    return nil
}

func main() {
    r := gin.Default()
    r.POST("/upload", uploadFile)
    r.Run()
}

这个示例实现了大文件分块上传的主要逻辑:

  1. 定义文件块大小blockSize为10M
  2. 接收文件和名称,打开本地文件准备上传
  3. 创建文件对象,记录文件大小,块数等信息
  4. 如果有上次未完成的上传,根据块号续传未上传的部分
  5. 否则开始分块上传,逐个上传文件块
  6. 上传完成后返回成功
  7. uploadBlock函数负责上传单个文件块

这样就实现了大文件分块传输的功能。可以在界面上选择大文件进行上传,会自动进行分块传输。

上一篇 下一篇

猜你喜欢

热点阅读