Go中io.Copy无法在os.File类型间复制数据问题咨询
问题根因
你遇到的问题核心是文件偏移量位置错误:
- 调用
os.Create()创建的文件,打开后默认偏移量在文件开头 - 执行
file1.WriteString("Some test data")写入14字节内容后,file1的当前偏移量会移动到14字节的位置(也就是内容末尾) io.Copy(dst, src)的逻辑是从src的当前偏移量开始读取内容,直到遇到EOF,此时src(file1)的偏移量已经在末尾,自然读不到任何内容,所以返回写入0字节,也不会抛出错误,因为EOF属于读取结束的正常状态- 你调用
readFile能读到file1的内容,是因为ioutil.ReadFile内部会重新打开目标文件,新打开的文件偏移量默认在开头,所以可以读到完整内容。
修复方案
在执行io.Copy之前,将file1的偏移量重置到文件开头即可,调用Seek方法:
// 放在io.Copy之前执行 _, err = file1.Seek(0, io.SeekStart) if err != nil { log.Fatal(err) }
修改后完整代码如下:
package main import ( "io" "io/ioutil" "log" "os" ) func main() { file1, err := os.Create("file1") if err != nil { log.Fatal(err) } file1.WriteString("Some test data") defer file1.Close() defer os.Remove(file1.Name()) log.Println("File1 Data : ", readFile(file1.Name())) file2, err := os.Create("file2") if err != nil { log.Fatal(err) } defer file2.Close() defer os.Remove(file2.Name()) // 新增:重置file1的偏移量到开头 _, err = file1.Seek(0, io.SeekStart) if err != nil { log.Fatal(err) } w, err := io.Copy(file2, file1) if err != nil { log.Fatal(err) } log.Println("Copied", w) log.Println("File2 Data : ", readFile(file2.Name())) } func readFile(fname string) string { data, err := ioutil.ReadFile(fname) if err != nil { log.Fatal(err) } return string(data) }
修改后运行输出如下:
2009/11/10 23:00:00 File1 Data : Some test data 2009/11/10 23:00:00 Copied 14 2009/11/10 23:00:00 File2 Data : Some test data
补充说明:如果你的场景中写入file1后还有其他操作,不方便直接Seek,也可以选择关闭file1后重新以只读模式打开,再传入io.Copy使用,效果一致。
内容的提问来源于stack exchange,提问作者akshay khairmode
相关产品推荐
相关产品推荐

