标准库之input&output
1、基本的io接口
在 io 包中最重要的是两个接口:Reader 和 Writer 接口。
1.1Reader接口
Reader 接口的定义如下:
1 2 3 | type Reader interface { Read(p []byte) (n int, err error) } |
Read 将 len(p) 个字节读取到 p 中。它返回读取的字节数 n(0 <= n <= len(p)) 以及任何遇到的错误。即使 Read 返回的 n < len(p),它也会在调用过程中占用 len(p) 个字节作为暂存空间。若可读取的数据不到 len(p) 个字节,Read 会返回可用数据,而不是等待更多数据。
当 Read 在成功读取 n > 0 个字节后遇到一个错误或 EOF (end-of-file),它会返回读取的字节数。它可能会同时在本次的调用中返回一个non-nil错误,或在下一次的调用中返回这个错误(且 n 为 0)。 一般情况下, Reader会返回一个非0字节数n, 若 n = len(p) 个字节从输入源的结尾处由 Read 返回,Read可能返回 err == EOF 或者 err == nil。并且之后的 Read() 都应该返回 (n:0, err:EOF)。
调用者在考虑错误之前应当首先处理返回的数据。这样做可以正确地处理在读取一些字节后产生的 I/O 错误,同时允许EOF的出现。
场景举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | func ReadFrom(reader io.Reader, num int) ([]byte, error) { p := make([]byte, num) n, err := reader.Read(p) if n > 0 { return p[:n], nil } return p, err } main(){ // 从标准输入读取 data, err = ReadFrom(os.Stdin, 11) // 从普通文件读取,其中 file 是 os.File 的实例 data, err = ReadFrom(file, 9) // 从字符串读取 data, err = ReadFrom(strings.NewReader( "from string" ), 12) } |
1.2Writer接口
Writer 接口的定义如下:
1 2 3 | type Writer interface { Write(p []byte) (n int, err error) } |
Write 将 len(p) 个字节从 p 中写入到基本数据流中。它返回从 p 中被写入的字节数 n(0 <= n <= len(p))以及任何遇到的引起写入提前停止的错误。若 Write 返回的 n < len(p),它就必须返回一个 非nil 的错误。
场景举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //在使用 Go 语言进行 Web 开发时,http.ResponseWriter 是最基本的类型之一,它本身是一个 Interface 类,原型如下:<br>type ResponseWriter interface { Header() Header Write([]byte) (int, error) WriteHeader(int) } <br> //<strong>直接调用 Write() 写入一串 []byte</strong> func helloHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set( "Content-Type" , "text/plain" ) w.Write([]byte( "Hello World" )) return } func main() { http.HandleFunc( "/" , helloHandler) http.ListenAndServe( ":8080" , nil) } |
1.3实现了 io.Reader 接口或 io.Writer 接口的类型
围绕io.Reader/Writer
,有几个常用的实现:
- net.Conn, os.Stdin, os.File: 网络、标准输入输出、文件的流读取
- strings.Reader: 把字符串抽象成Reader
- bytes.Reader: 把
[]byte
抽象成Reader - bytes.Buffer: 把
[]byte
抽象成Reader和Writer - bufio.Reader/Writer: 抽象成带缓冲的流读取(比如按行读写)
2、ReaderAt 和 WriterAt 接口
2.1ReaderAt 接口
1 2 3 | type ReaderAt interface { ReadAt(p []byte, off int64) (n int, err error) } |
ReadAt 从基本输入源的偏移量 off 处开始,将 len(p) 个字节读取到 p 中。它返回读取的字节数 n(0 <= n <= len(p))以及任何遇到的错误。
当 ReadAt 返回的 n < len(p) 时,它就会返回一个 非nil 的错误来解释 为什么没有返回更多的字节。在这一点上,ReadAt 比 Read 更严格。
即使 ReadAt 返回的 n < len(p),它也会在调用过程中使用 p 的全部作为暂存空间。若可读取的数据不到 len(p) 字节,ReadAt 就会阻塞,直到所有数据都可用或一个错误发生。 在这一点上 ReadAt 不同于 Read。
若 n = len(p) 个字节从输入源的结尾处由 ReadAt 返回,Read可能返回 err == EOF 或者 err == nil
若 ReadAt 携带一个偏移量从输入源读取,ReadAt 应当既不影响偏移量也不被它所影响。
可对相同的输入源并行执行 ReadAt 调用。
场景举例:
1 2 3 4 5 6 7 | reader := strings.NewReader( "Go语言中文网" ) p := make([]byte, 6) n, err := reader.ReadAt(p, 2) if err != nil { panic(err) } fmt.Printf( "%s, %d\n" , p, n) |
2.2WriterAt 接口
1 2 3 | type WriterAt interface { WriteAt(p []byte, off int64) (n int, err error) } |
WriteAt 从 p 中将 len(p) 个字节写入到偏移量 off 处的基本数据流中。它返回从 p 中被写入的字节数 n(0 <= n <= len(p))以及任何遇到的引起写入提前停止的错误。若 WriteAt 返回的 n < len(p),它就必须返回一个 非nil 的错误。
若 WriteAt 携带一个偏移量写入到目标中,WriteAt 应当既不影响偏移量也不被它所影响。
若被写区域没有重叠,可对相同的目标并行执行 WriteAt 调用。
场景举例:
1 2 3 4 5 6 7 8 9 10 11 | file, err := os.Create( "writeAt.txt" ) if err != nil { panic(err) } defer file.Close() file.WriteString( "Golang中文社区——这里是多余" ) n, err := file.WriteAt([]byte( "Go语言中文网" ), 24) if err != nil { panic(err) } fmt.Println(n) |
3、ReaderFrom 和 WriterTo 接口
3.1ReaderFrom 接口
ReaderFrom 的定义如下:
1 2 3 | type ReaderFrom interface { ReadFrom(r Reader) (n int64, err error) } |
ReadFrom 从 r 中读取数据,直到 EOF 或发生错误。其返回值 n 为读取的字节数。除 io.EOF 之外,在读取过程中遇到的任何错误也将被返回。
如果 ReaderFrom 可用,Copy 函数就会使用它。
ReadFrom 方法不会返回 err == EOF。
场景举例:
1 2 3 4 5 6 7 8 9 | //将文件中的数据全部读取(显示在标准输出) file, err := os.Open( "writeAt.txt" ) if err != nil { panic(err) } defer file.Close() writer := bufio.NewWriter(os.Stdout) writer.ReadFrom(file) writer.Flush() |
3.2WriterTo接口
1 2 3 | type WriterTo interface { WriteTo(w Writer) (n int64, err error) } |
WriteTo 将数据写入 w 中,直到没有数据可写或发生错误。其返回值 n 为写入的字节数。 在写入过程中遇到的任何错误也将被返回。
如果 WriterTo 可用,Copy 函数就会使用它。
场景举例:
1 2 3 | //将一段文本输出到标准输出 reader := bytes.NewReader([]byte( "Go语言中文网" )) reader.WriteTo(os.Stdout) |
4、Seeker 接口
接口定义如下:
1 2 3 | type Seeker interface { Seek(offset int64, whence int) (ret int64, err error) } |
Seek 设置下一次 Read 或 Write 的偏移量为 offset,它的解释取决于 whence: 0 表示相对于文件的起始处,1 表示相对于当前的偏移,而 2 表示相对于其结尾处。 Seek 返回新的偏移量和一个错误,如果有的话。
场景举例:
1 2 3 4 5 | //获取倒数第二个字符 reader := strings.NewReader( "Go语言中文网" ) reader.Seek(-6, io.SeekEnd) r, _, _ := reader.ReadRune() fmt.Printf( "%c\n" , r) |
5、Closer接口
1 2 3 | type Closer interface { Close() error } |
该接口比较简单,只有一个 Close() 方法,用于关闭数据流。
文件 (os.File)、归档(压缩包)、数据库连接、Socket 等需要手动关闭的资源都实现了 Closer 接口。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)