为何os.Create创建文件后无法直接用io.Copy写入内容?
问题原因与解决方案
你遇到的问题核心是文件读写指针的位置问题:
os.Create创建文件后,返回的*os.File对象读写指针初始在文件起始位置(偏移量0)。- 当你使用
multipart.Writer往这个文件写入表单数据时,每写入一段内容,指针就会向后移动,直到所有数据写完后,指针停在文件的末尾位置。 - 此时直接调用
io.Copy将文件内容复制到请求体,因为指针已经在末尾,没有可读取的数据,所以返回0字节写入量。 - 而关闭文件重新打开时,新的文件对象的读写指针会重置到起始位置,这时候
io.Copy就能读取到之前写入的所有表单数据,因此操作成功。
最简修复方案
不需要关闭重新打开文件,只需要在写完表单数据后,将文件指针重置到起始位置即可,使用file.Seek(0, io.SeekStart)实现:
package main import ( "io" "mime/multipart" "net/http" "os" ) func main() { file, err := os.Create("temp.txt") if err != nil { panic(err) } defer file.Close() writer := multipart.NewWriter(file) defer writer.Close() // 写入表单字段 field, err := writer.CreateFormField("name") if err != nil { panic(err) } _, err = field.Write([]byte("test")) if err != nil { panic(err) } // 写入附件 part, err := writer.CreateFormFile("file", "test.txt") if err != nil { panic(err) } _, err = part.Write([]byte("file content")) if err != nil { panic(err) } // 重置文件指针到起始位置 _, err = file.Seek(0, io.SeekStart) if err != nil { panic(err) } // 构建并发送请求 req, err := http.NewRequest("POST", "https://example.com/upload", file) if err != nil { panic(err) } req.Header.Set("Content-Type", writer.FormDataContentType()) client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() }
这样就能在不重新打开文件的前提下,正确读取到之前写入的表单数据,完成请求发送。
内容的提问来源于stack exchange,提问作者yuta
相关产品推荐
相关产品推荐

