io 包能做什么
Go 的 io 包提供 I/O 的基本原语和接口:Reader、Writer 这类接口定义读写动作,Copy、Pipe 这类函数负责在它们之间衔接。
1. io 包接口和类型
Reader接口Reader接口是所有读取操作的基础,它定义了一个方法Read:gopackage io type Reader interface { Read(p []byte) (n int, err error) }Read方法从数据源读取最多 len(p) 字节的数据到 p 中,并返回实际读取的字节数和可能的错误。示例:
gopackage main import ( "fmt" "strings" "io" ) func main() { r := strings.NewReader("Hello, Go!") buf := make([]byte, 4) for { n, err := r.Read(buf) if err == io.EOF { break } if err != nil { fmt.Println("Error reading:", err) break } fmt.Printf("Read %d bytes: %s\n", n, string(buf[:n])) } }Writer接口Writer接口定义了一个方法Write:gopackage io type Writer interface { Write(p []byte) (n int, err error) }Write方法将 p 中的数据写入到目标,并返回写入的字节数和可能的错误。示例:
gopackage main import ( "fmt" "strings" ) func main() { var w strings.Builder n, err := w.Write([]byte("Hello, Go!")) if err != nil { fmt.Println("Error writing:", err) return } fmt.Printf("Wrote %d bytes: %s\n", n, w.String()) }Closer接口Closer接口用于关闭资源,定义了一个方法Close:gopackage io type Closer interface { Close() error }Close方法关闭资源,并返回可能的错误。ReadWriter接口ReadWriter接口结合了Reader和Writer接口,定义了两个方法:gopackage io type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } type ReadWriter interface { Reader Writer }示例:
gopackage main import ( "fmt" "io" "os" ) func main() { file, err := os.Create("example.txt") if err != nil { fmt.Println("Error creating file:", err) return } defer file.Close() rw := io.Writer(file) rw.Write([]byte("Hello, File!")) }PipePipe函数创建一对连接的Reader和Writer,它们可以用于在不同的协程之间传递数据。gopackage io type PipeReader struct { // contains filtered or unexported fields } type PipeWriter struct { // contains filtered or unexported fields } func Pipe() (*PipeReader, *PipeWriter)示例:
gopackage main import ( "fmt" "io" ) func main() { pr, pw := io.Pipe() go func() { defer pw.Close() pw.Write([]byte("Hello, Pipe!")) }() data, err := io.ReadAll(pr) if err != nil { fmt.Println("Error reading from pipe:", err) return } fmt.Println("Read from pipe:", string(data)) }LimitedReaderLimitedReader限制Reader读取的字节数:gopackage io type Reader interface { Read(p []byte) (n int, err error) } type LimitedReader struct { R Reader N int64 }示例:
gopackage main import ( "fmt" "io" "strings" ) func main() { r := io.LimitReader(strings.NewReader("Hello, Go!"), 5) data, _ := io.ReadAll(r) fmt.Println("Limited read:", string(data)) }MultiReaderMultiReader连接多个Reader,依次读取每个Reader,前一个读完(返回 EOF)后再读下一个。gopackage io type MultiReader struct { // contains filtered or unexported fields }示例:
gopackage main import ( "fmt" "io" "strings" ) func main() { r1 := strings.NewReader("Hello, ") r2 := strings.NewReader("World!") mr := io.MultiReader(r1, r2) data, _ := io.ReadAll(mr) fmt.Println("Multi-read:", string(data)) }PipeReader和PipeWriterPipeReader和PipeWriter是Pipe函数返回的类型,它们用于在管道中进行读写操作。示例:
gopackage main import ( "fmt" "io" ) func main() { pr, pw := io.Pipe() go func() { defer pw.Close() pw.Write([]byte("Hello, Pipe!")) }() data, err := io.ReadAll(pr) if err != nil { fmt.Println("Error reading from pipe:", err) return } fmt.Println("Read from pipe:", string(data)) }TeeReaderTeeReader同时将读取的数据写入另一个Writer并返回原始数据。gopackage io type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } func TeeReader(r Reader, w Writer) Reader示例:
gopackage main import ( "fmt" "io" "strings" ) func main() { var output strings.Builder r := io.TeeReader(strings.NewReader("Hello, TeeReader!"), &output) data, _ := io.ReadAll(r) fmt.Println("Read data:", string(data)) fmt.Println("Written to output:", output.String()) }
2. 常用函数
io.Copyio.Copy从一个Reader复制数据到一个Writer。gopackage io type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } func Copy(dst Writer, src Reader) (written int64, err error)示例:
gopackage main import ( "fmt" "io" "strings" ) func main() { src := strings.NewReader("Hello, Copy!") var dst strings.Builder _, err := io.Copy(&dst, src) if err != nil { fmt.Println("Error copying:", err) return } fmt.Println("Copied data:", dst.String()) }io.ReadAllio.ReadAll读取所有数据直到 EOF。gopackage io type Reader interface { Read(p []byte) (n int, err error) } func ReadAll(r Reader) ([]byte, error)示例:
gopackage main import ( "fmt" "io" "strings" ) func main() { r := strings.NewReader("Hello, ReadAll!") data, err := io.ReadAll(r) if err != nil { fmt.Println("Error reading:", err) return } fmt.Println("Read all data:", string(data)) }io.ReadFullio.ReadFull读取指定长度的数据。gopackage io type Reader interface { Read(p []byte) (n int, err error) } func ReadFull(r Reader, buf []byte) (n int, err error)示例:
gopackage main import ( "fmt" "io" "strings" ) func main() { r := strings.NewReader("Hello, ReadFull!") buf := make([]byte, 5) n, err := io.ReadFull(r, buf) if err != nil { fmt.Println("Error reading full data:", err) return } fmt.Printf("Read %d bytes: %s\n", n, string(buf)) }io.Seeker接口与io.SeekStart等常量io.Seeker接口封装了在数据流中设置当前位置的能力(如*os.File),io.SeekStart、io.SeekCurrent、io.SeekEnd是Seek方法使用的基准常量。gopackage io type Seeker interface { Seek(offset int64, whence int) (int64, error) } const ( SeekStart = 0 // 相对于文件起点 SeekCurrent = 1 // 相对于当前位置 SeekEnd = 2 // 相对于文件结尾 )示例:
gopackage main import ( "fmt" "io" "os" ) func main() { file, err := os.Create("example.txt") if err != nil { fmt.Println("Error creating file:", err) return } defer file.Close() file.Write([]byte("Hello, Seek!")) file.Seek(0, io.SeekStart) buf := make([]byte, 5) file.Read(buf) fmt.Println("Seeked data:", string(buf)) }strings.NewReaderGo 的
io包没有直接把字符串转为Reader的函数,通常使用strings包的NewReader。gopackage strings // Reader 是标准库 strings.Reader 的简化摘录 type Reader struct { s string i int } func NewReader(s string) *Reader示例:
gopackage main import ( "fmt" "io" "strings" ) func main() { r := strings.NewReader("Hello, StringReader!") data, _ := io.ReadAll(r) fmt.Println("Read from StringReader:", string(data)) }io.StringWriterio.StringWriter是一个接口,表示支持一次性写入字符串的Writer(如*strings.Builder)。gopackage io type StringWriter interface { WriteString(s string) (n int, err error) }示例:
gopackage main import ( "fmt" "io" "strings" ) func main() { var sb strings.Builder var w io.StringWriter = &sb w.WriteString("Hello, StringWriter!") fmt.Println("Written data:", sb.String()) }
Reader 和 Writer 是 Go I/O 体系里被引用最多的两个接口,Copy、ReadAll、ReadFull 覆盖了大多数数据搬运场景。函数写成接收 io.Reader 的形式,就能同时接住文件和内存中的数据。