上传大文件-错误VirtualAllocofx字节失败,errno=1455致命错误:内存不足
我有 10GB 的大文件,我试图通过 Postman 在 Go 中使用 multipart/form-data 上传。由于我不太了解 Go 中文件上传的工作原理,所以我在 YouTube 上找到了教程。
文件上传适用于较小的文件,但在较大的文件上总是崩溃并显示以下消息:“运行时:9193373696 字节的 VirtualAlloc 失败,errno=1455 致命错误:内存不足”。这是我正在努力工作的代码:
err := r.ParseMultipartForm(500 << 20)
if err != nil {
fmt.Fprintln(w, err)
}
file, handler, err := r.FormFile("file")
if err != nil {
fmt.Fprintln(w, err)
}
fmt.Fprintln(w, handler.Filename)
fmt.Fprintln(w, handler.Size)
fmt.Fprintln(w, handler.Header.Get("Content-type"))
defer file.Close()
saveLocation := "C:UsersPcgosrcgithub.comtestuptest"
tempFile, err := ioutil.TempFile(saveLocation, "upload")
if err != nil {
fmt.Fprintln(w, err)
}
defer tempFile.Close()
fileBytes, err := ioutil.ReadAll(file)
if err != nil {
fmt.Fprintln(w, err)
}
tempFile.Write(fileBytes)
回答
使用ParseMultipartForm()将要求您提供最大内存分配来临时存储上传的文件。如果您的文件很大(并且大于您分配的内存数量),那么这对您的内存资源来说是个坏消息。
来自文档:
ParseMultipartForm 将请求正文解析为 multipart/form-data。整个请求正文被解析,其文件部分的总共 maxMemory 字节存储在内存中,其余部分存储在磁盘上的临时文件中。ParseMultipartForm 必要时调用 ParseForm。对 ParseMultipartForm 调用一次后,后续调用无效。
根据您的错误消息,我们可以判断问题的根本原因是由于上传的文件大于您分配的内存,即500 << 20.
对于处理大文件上传,我建议查看一下MultipartReader()。
来自文档:
MultipartReader 返回 MIME 多部分阅读器,如果这是多部分/表单数据或多部分/混合 POST 请求,否则返回 nil 和错误。使用此函数代替 ParseMultipartForm 将请求正文作为流处理。
这是一种更快的方法并且不会消耗太多资源,这是因为我们将具有使用 将主体(这是一个流数据)直接存储到目标文件中的优势io.Copy(),而不是先将其写入临时存储。
一个简单的使用示例MultipartReader():
reader, err := r.MultipartReader()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
for {
part, err := reader.NextPart()
if err == io.EOF {
break
}
fmt.Println(part.FileName()) // prints file name
fmt.Println(part.FormName()) // prints form key, in yor case it's "file"
saveLocation := "C:UsersPcgosrcgithub.comtestuptest"
dst, err := os.Create(saveLocation)
if dst != nil {
defer dst.Close()
}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if _, err := io.Copy(dst, part); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
参考:https : //pkg.go.dev/net/http#Request.ParseMultipartForm