美文网首页
2023-04-29 Go基础——gin

2023-04-29 Go基础——gin

作者: Lovevivi | 来源:发表于2024-03-06 21:40 被阅读0次

    用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函数负责上传单个文件块

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

    相关文章

      网友评论

          本文标题:2023-04-29 Go基础——gin

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