Go 复制文件
最后修改日期 2025 年 4 月 29 日
本教程演示了如何使用各种方法在 Golang 中复制文件。我们探讨了五种不同的文件复制方法,展示了不同的 Go 包和函数。每种方法根据用例提供独特的优势,例如简单性、性能或细粒度控制。
我们使用 Go 标准库中的函数,如 ioutil.ReadFile
、ioutil.WriteFile
、io.Copy
、File.Read
、File.Write
等,以高效地执行文件复制操作。
使用 ioutil 复制
第一个示例使用 ioutil
包来实现一种直接的方法。它将整个源文件读取到内存中,然后将其写入目标文件,由于其简单性和少量代码,非常适合小型文件。
package main import ( "io/ioutil" "log" ) func main() { src := "words.txt" dest := "words2.txt" bytesRead, err := ioutil.ReadFile(src) if err != nil { log.Fatal(err) } err = ioutil.WriteFile(dest, bytesRead, 0644) if err != nil { log.Fatal(err) } }
ioutil.ReadFile
函数将源文件的全部内容读取到一个字节切片中,并在内部处理文件的打开和关闭。ioutil.WriteFile
函数将此字节切片写入目标文件,使用指定的权限 (0644) 创建或覆盖它。此方法简洁,但由于内存使用,可能不适用于非常大的文件。
使用 io.Copy
第二个示例采用 io.Copy
函数,该函数将数据从源文件流式传输到目标文件。此方法内存效率高,因为它避免将整个文件加载到内存中,因此适用于大型文件。
package main import ( "io" "log" "os" ) func main() { src := "words.txt" dst := "words2.txt" fin, err := os.Open(src) if err != nil { log.Fatal(err) } defer fin.Close() fout, err := os.Create(dst) if err != nil { log.Fatal(err) } defer fout.Close() _, err = io.Copy(fout, fin) if err != nil { log.Fatal(err) } }
我们使用 os.Open
打开源文件,使用 os.Create
创建或截断目标文件。它们返回文件句柄,这些句柄传递给 io.Copy
,io.Copy
以块的形式高效地流式传输数据。defer
语句确保在复制后关闭两个文件,防止资源泄漏。此方法平衡了简单性和性能。
使用 File.Read 和 File.Write
第三个示例使用 File.Read
和 File.Write
来手动控制复制过程。它以块的形式读取文件,提供了在复制过程中处理数据的灵活性,这对于自定义转换或监控进度非常有用。
package main import ( "io" "log" "os" ) func main() { src := "words.txt" dst := "words2.txt" buf := make([]byte, 1024) fin, err := os.Open(src) if err != nil { log.Fatal(err) } defer fin.Close() fout, err := os.Create(dst) if err != nil { log.Fatal(err) } defer fout.Close() for { n, err := fin.Read(buf) if err != nil && err != io.EOF { log.Fatal(err) } if n == 0 { break } if _, err := fout.Write(buf[:n]); err != nil { log.Fatal(err) } } }
创建一个 1024 字节的缓冲区,使用 File.Read
读取源文件的块。循环继续,直到没有读取到字节 (n == 0),表示文件结束。每个块使用 File.Write
写入目标文件。io.EOF
检查区分读取错误和文件结束。此方法提供了细粒度控制,但需要更多的代码。
使用 os.ReadFile 和 os.WriteFile
第四个示例使用 os.ReadFile
和 os.WriteFile
,这是已弃用的 ioutil
函数的现代替代品。此方法与第一个示例类似,但使用了更新的 API,确保与新 Go 版本的兼容性。
package main import ( "log" "os" ) func main() { src := "words.txt" dst := "words2.txt" data, err := os.ReadFile(src) if err != nil { log.Fatal(err) } err = os.WriteFile(dst, data, 0644) if err != nil { log.Fatal(err) } }
os.ReadFile
函数将源文件的全部内容读取到一个字节切片中,类似于 ioutil.ReadFile
。os.WriteFile
函数使用指定的权限 (0644) 将数据写入目标文件。此方法很简单,并且在现代 Go 程序中推荐用于小型文件,因为它使用了 os
包中未弃用的函数。
使用 io.CopyBuffer 复制
第五个示例将 io.CopyBuffer
与自定义缓冲区结合使用,提供了第二个示例的一个变体。它允许对缓冲区大小进行显式控制,这可以优化针对特定文件大小或硬件的性能。
package main import ( "io" "log" "os" ) func main() { src := "words.txt" dst := "words2.txt" buf := make([]byte, 4096) fin, err := os.Open(src) if err != nil { log.Fatal(err) } defer fin.Close() fout, err := os.Create(dst) if err != nil { log.Fatal(err) } defer fout.Close() _, err = io.CopyBuffer(fout, fin, buf) if err != nil { log.Fatal(err) } }
我们分配了一个 4096 字节的缓冲区用于复制,比 io.Copy
使用的默认缓冲区大。io.CopyBuffer
函数使用此缓冲区将数据从源文件流式传输到目标文件。此方法对大型文件来说很高效,并且允许调整缓冲区大小以提高性能,同时保持流式方法的简单性。
来源
在本文中,我们在 Golang 中复制了文件。