golang Client 客户端 大文件上传 (带进度条)

需要用到环形缓冲区进行读写:golang 环形缓冲区

网上的例子大部分都是把文件全部缓存到内存上传,大文件隐患不小,这个的好处就是缓冲区小,全靠流输入输出。

go get github.com/mgr9525/go-ruisutil
func randomBoundary() string {
    var buf [30]byte
    _, err := io.ReadFull(rand.Reader, buf[:])
    if err != nil {
        panic(err)
    }
    return fmt.Sprintf("%x", buf[:])
}
/*
 * url:上传地址
 * flpath:上传文件地址
 */
func upload(url,flpath string){
    body := ruisUtil.NewCircleByteBuffer(10240)
    boundary:=randomBoundary()
    boundarybytes := []byte("\r\n--" + boundary + "\r\n")
    endbytes := []byte("\r\n--" + boundary + "--\r\n")

    reqest, err := http.NewRequest("POST", url, body)
    if err != nil { panic(err) }
    reqest.Header.Add("Connection", "keep-alive")
    reqest.Header.Add("Content-Type", "multipart/form-data; charset=utf-8; boundary="+boundary)
    go func() {
        //defer ruisRecovers("upload.run")
        f, err := os.OpenFile(flpath, os.O_RDONLY, 0666)  //其实这里的 O_RDWR应该是 O_RDWR|O_CREATE,也就是文件不存在的情况下就建一个空文件,但是因为windows下还有BUG,如果使用这个O_CREATE,就会直接清空文件,所以这里就不用了这个标志,你自己事先建立好文件。
        if err != nil { panic(err) }
        stat, err := f.Stat()    //获取文件状态
        if err != nil { panic(err) }
        defer f.Close()

        header:=fmt.Sprintf("Content-Disposition: form-data; name=\"upfile\"; filename=\"%s\"\r\nContent-Type: application/octet-stream\r\n\r\n",stat.Name())
        body.Write(boundarybytes)
        body.Write([]byte(header))

        fsz:=float64(stat.Size())
        fupsz:=float64(0)
        buf:=make([]byte,1024)
        for {
            time.Sleep(10*time.Microsecond)//减缓上传速度,看进度效果
            n,err:=f.Read(buf)
            if n>0{
                nz,_:=body.Write(buf[0:n])
                fupsz+=float64(nz)
                progress := strconv.Itoa(int((fupsz / fsz) * 100))+"%"
                fmt.Println("upload:",progress,"|",strconv.FormatFloat(fupsz,'f',0,64),"/",stat.Size())
            }
            if err==io.EOF {
                break
            }
        }
        body.Write(endbytes)
        body.Write(nil)//输入EOF,表示数据写完了
    }()
    resp,err:=http.DefaultClient.Do(reqest)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    if resp.StatusCode==200{
        fmt.Println("上传成功")
    }else{
        fmt.Println("上传失败,StatusCode:",resp.StatusCode)
    }
}

 

调用:

upload("http://localhost:8080/upload","e:\\123.txt")

 

    原文作者:LinskRuis
    原文地址: https://blog.csdn.net/mgr9525/article/details/86770197
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞