gpt4 book ai didi

http - 如何在 go 中以流的形式上传文件?

转载 作者:IT王子 更新时间:2023-10-29 01:13:38 56 4
gpt4 key购买 nike

有很多关于在 go 中使用 http.Request 发布文件的教程,但几乎都是这样开始的:

file, err := os.Open(path)
if err != nil {
return nil, err
}
fileContents, err := ioutil.ReadAll(file)

也就是说,您将整个文件读入内存,然后将其转换为 Buffer 并将其传递到请求中,如下所示:

func send(client *http.Client, file *os.File, endpoint string) {
body := &bytes.Buffer{}
io.Copy(body, file)
req, _ := http.NewRequest("POST", endpoint, body)
resp, _ := client.Do(req)
}

如果您想发布一个大文件并避免将其读入内存,而是将文件分 block 处理……您会怎么做?

最佳答案

如果需要设置Content-Length,可以手动设置。以下代码段是将文件和额外参数作为流上传的示例(代码基于 Buffer-less Multipart POST in Golang )

//NOTE: for simplicity, error check is omitted
func uploadLargeFile(uri, filePath string, chunkSize int, params map[string]string) {
//open file and retrieve info
file, _ := os.Open(filePath)
fi, _ := file.Stat()
defer file.Close()

//buffer for storing multipart data
byteBuf := &bytes.Buffer{}

//part: parameters
mpWriter := multipart.NewWriter(byteBuf)
for key, value := range params {
_ = mpWriter.WriteField(key, value)
}

//part: file
mpWriter.CreateFormFile("file", fi.Name())
contentType := mpWriter.FormDataContentType()

nmulti := byteBuf.Len()
multi := make([]byte, nmulti)
_, _ = byteBuf.Read(multi)

//part: latest boundary
//when multipart closed, latest boundary is added
mpWriter.Close()
nboundary := byteBuf.Len()
lastBoundary := make([]byte, nboundary)
_, _ = byteBuf.Read(lastBoundary)

//calculate content length
totalSize := int64(nmulti) + fi.Size() + int64(nboundary)
log.Printf("Content length = %v byte(s)\n", totalSize)

//use pipe to pass request
rd, wr := io.Pipe()
defer rd.Close()

go func() {
defer wr.Close()

//write multipart
_, _ = wr.Write(multi)

//write file
buf := make([]byte, chunkSize)
for {
n, err := file.Read(buf)
if err != nil {
break
}
_, _ = wr.Write(buf[:n])
}
//write boundary
_, _ = wr.Write(lastBoundary)
}()

//construct request with rd
req, _ := http.NewRequest("POST", uri, rd)
req.Header.Set("Content-Type", contentType)
req.ContentLength = totalSize

//process request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
} else {
log.Println(resp.StatusCode)
log.Println(resp.Header)

body := &bytes.Buffer{}
_, _ = body.ReadFrom(resp.Body)
resp.Body.Close()
log.Println(body)
}
}

关于http - 如何在 go 中以流的形式上传文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39761910/

56 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com