Golang如何实现一次性上传多个文件
Golang如何实现一次性上传多个文件 我阅读了这篇博客和这个问题及其答案,但发现它们只讨论了单个文件。
// 解析我们的多部分表单,10 << 20 指定了最大
// 上传文件大小为 10 MB。
r.ParseMultipartForm(10 << 20)
// FormFile 返回给定键 `myFile` 的第一个文件
// 它还返回 FileHeader,以便我们可以获取文件名、
// 头部信息和文件大小
file, handler, err := r.FormFile("myFile")
if err != nil {
fmt.Println("Error Retrieving the File")
fmt.Println(err)
return
}
defer file.Close()
我如何一次性上传多个文件?
如果我使用下面的 JavaScript 代码上传多个文件,如何在 GO 服务器端读取和处理它?
const formData = new FormData();
const photos = document.querySelector('input[type="file"][multiple]');
formData.append('title', 'My Vegas Vacation');
for (let i = 0; i < photos.files.length; i++) {
formData.append('photos', photos.files[i]);
}
fetch('https://example.com/posts', {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(result => {
console.log('Success:', result);
})
.catch(error => {
console.error('Error:', error);
});
更多关于Golang如何实现一次性上传多个文件的实战教程也可以访问 https://www.itying.com/category-94-b0.html
2 回复
更多关于Golang如何实现一次性上传多个文件的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中处理多文件上传,可以使用r.MultipartForm或r.FormFile的变体。以下是两种实现方式:
方法1:使用MultipartForm
func uploadHandler(w http.ResponseWriter, r *http.Request) {
// 解析表单,限制上传大小
err := r.ParseMultipartForm(32 << 20) // 32MB
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// 获取所有文件
files := r.MultipartForm.File["photos"] // "photos"是前端字段名
for i, fileHeader := range files {
// 打开文件
file, err := fileHeader.Open()
if err != nil {
http.Error(w, fmt.Sprintf("Error opening file %d: %v", i, err), http.StatusInternalServerError)
return
}
defer file.Close()
// 创建目标文件
dst, err := os.Create(fileHeader.Filename)
if err != nil {
http.Error(w, fmt.Sprintf("Error creating file %d: %v", i, err), http.StatusInternalServerError)
return
}
defer dst.Close()
// 复制文件内容
if _, err := io.Copy(dst, file); err != nil {
http.Error(w, fmt.Sprintf("Error saving file %d: %v", i, err), http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "Uploaded file %d: %s\n", i, fileHeader.Filename)
}
}
方法2:使用FormFile的变体
func uploadHandler(w http.ResponseWriter, r *http.Request) {
// 解析表单
err := r.ParseMultipartForm(32 << 20)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// 获取表单
form := r.MultipartForm
// 遍历所有文件
for fieldName, fileHeaders := range form.File {
for _, fileHeader := range fileHeaders {
file, err := fileHeader.Open()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer file.Close()
// 保存文件
dst, err := os.Create("./uploads/" + fileHeader.Filename)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer dst.Close()
if _, err := io.Copy(dst, file); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "Field: %s, File: %s uploaded\n", fieldName, fileHeader.Filename)
}
}
}
方法3:流式处理(适合大文件)
func uploadHandler(w http.ResponseWriter, r *http.Request) {
// 创建解析器
reader, err := r.MultipartReader()
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
for {
part, err := reader.NextPart()
if err == io.EOF {
break
}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 只处理文件部分
if part.FileName() != "" {
// 创建目标文件
dst, err := os.Create("./uploads/" + part.FileName())
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer dst.Close()
// 复制文件内容
if _, err := io.Copy(dst, part); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "Uploaded: %s\n", part.FileName())
}
part.Close()
}
}
完整示例
package main
import (
"fmt"
"io"
"net/http"
"os"
"path/filepath"
)
func uploadHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// 创建上传目录
uploadDir := "./uploads"
os.MkdirAll(uploadDir, 0755)
// 解析表单
err := r.ParseMultipartForm(32 << 20)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// 获取所有文件
files := r.MultipartForm.File["photos"]
var uploadedFiles []string
for _, fileHeader := range files {
// 打开文件
file, err := fileHeader.Open()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer file.Close()
// 创建安全文件名
safeFileName := filepath.Base(fileHeader.Filename)
filePath := filepath.Join(uploadDir, safeFileName)
// 创建目标文件
dst, err := os.Create(filePath)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer dst.Close()
// 复制文件内容
if _, err := io.Copy(dst, file); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
uploadedFiles = append(uploadedFiles, safeFileName)
}
// 返回响应
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{"status": "success", "uploaded_files": %d, "files": %v}`,
len(uploadedFiles), uploadedFiles)
}
func main() {
http.HandleFunc("/upload", uploadHandler)
http.ListenAndServe(":8080", nil)
}
这些方法都能处理前端使用相同字段名(如"photos")上传的多个文件。r.MultipartForm.File["photos"]会返回一个[]*multipart.FileHeader切片,包含所有上传的文件。

