• 简体中文
  • Example: io.Copy

    简明示例

    io.Copy 是一个高效的数据管道函数,就像一条高效的数据直连管道。它能将数据直接从输入流(io.Reader)源源不断地抽送到输出流(io.Writer),期间不会把整个文件一次性读入内存,因此非常适合处理大文件或网络流。

    package main
    
    import (
        "fmt"
        "io"
        "os"
        "strings"
    )
    
    func main() {
        // 1. 初始化源端 (Reader):一个模拟的字符串流
        src := strings.NewReader("Hello,io.Copy from gobase.net.\n")
        // 2. 定义目的地 (Writer): 这里是标准输出(控制台)
        dst := os.Stdout
        // 3. 开始数据传输,它会自动循环读取并写入,直到 src 返回 io.EOF 
        written, err := io.Copy(dst, src)
        if err != nil {
            fmt.Fprintf(os.Stderr, "复制过程中发生错误: %v\n", err)
            return
        }
    	// 4. written 返回的是实际传输的字节数
    	fmt.Printf("\n[传输完成] 成功搬运了 %d 个字节。\n", written)
    }
    

    输出

    Hello,io.Copy from gobase.net.
    
    [传输完成] 成功搬运了 31 个字节。
    零内存高效搬运

    io.Copy 是一个高效的搬运工,在底层通过默认 32 KB 的临时缓冲区实现高效的数据流转发,占用资源极低, 若需要根据业务场景调整缓冲区大小,可使用标准库的另外来一个函数func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error):

    • dst / src:目标写入流与源读取流。
    • buf:手动传入的复用切片(若传入 nil,则系统会自动分配 32 KB 缓冲区,等同io.Copy)。

    使用io.Copy进行大文件复制示例

    在实际开发中,处理几百 MB 甚至数 GB 的大文件(如视频、压缩包、日志等)时,如果使用 os.ReadFile 或 io.ReadAll 一次性将文件读入内存,极易引发 OOM(内存溢出)。 使用io.Copy 复制 10 MB 还是 10 GB 的文件,可以让所占用的内存始终保持在极低的水平。

    package main
    
    import (
    	"fmt"
    	"io"
    	"os"
    	"time"
    )
    
    func main() {
    	start := time.Now()
    
    	// 1. 打开源文件(只读)
    	srcFile, err := os.Open("large_video.mp4")
    	if err != nil {
    		fmt.Fprintf(os.Stderr, "无法打开源文件: %v\n", err)
    		return
    	}
    	defer srcFile.Close() // 确保资源最终被释放
    
    	// 2. 创建目标文件(若存在则清空,权限为 0666)
    	dstFile, err := os.Create("large_video_backup.mp4")
    	if err != nil {
    		fmt.Fprintf(os.Stderr, "无法创建目标文件: %v\n", err)
    		return
    	}
    	defer dstFile.Close()
    
    	// 3. 使用 io.Copy 建立管道,进行流式拷贝
    	// 此时内存中只有 32KB 的数据在流转
    	written, err := io.Copy(dstFile, srcFile)
    	if err != nil {
    		fmt.Fprintf(os.Stderr, "文件复制失败: %v\n", err)
    		return
    	}
    
    	// 4. 打印统计结果
    	duration := time.Since(start)
    	fmt.Printf("[复制成功]\n")
    	fmt.Printf("・传输数据: %.2f MB\n", float64(written)/(1024*1024))
    	fmt.Printf("・耗时时间: %v\n", duration)
    }