Go语言IO编程
该包为IO操作原语提供了基本的接口,它包装了IO操作原语的实现(例如os包中的类型)。除非特别说明,调用者不能假设接口中的方法可以被并行调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
const ( SeekStart = 0 // 相对于文件的起始位置进行Seek SeekCurrent = 1 // 相对于当前读取位置进行Seek SeekEnd = 2 // 相对于尾部进行Seek ) // 错误定义 // 由Read函数返回,表示没有更多可读的数据。用于优雅的结束文件读取(读到尾部了) var EOF = errors.New("EOF") // 在关闭的管道上进行读写 var ErrClosedPipe = errors.New("io: read/write on closed pipe") var ErrNoProgress = errors.New("multiple Read calls return no data or error")、 // 当提供的缓冲区不够存放读取到的数据时 var ErrShortBuffer = errors.New("short buffer") // 当写操作所要求的字节数不足时 var ErrShortWrite = errors.New("short write") // 在读取固定长度的块或者数据结构时,没有到预期的结尾位置即发生EOF var ErrUnexpectedEOF = errors.New("unexpected EOF") |
函数 | 说明 | ||||
Copy |
func Copy(dst Writer, src Reader) (written int64, err error) 从src读取数据并写入到dst,直到src的EOF。返回写入dst的字节数,操作成功则err为nil 实现方式:如果src实现了WriterTo接口,则调用src.WriteTo(dst);如果dst实现了ReaderFrom接口,则调用dst.ReadFrom(src) 示例代码:
|
||||
CopyBuffer |
func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) 和上面类似,只是拷贝时使用给定的缓冲区。如果buf为nil则自动创建一个缓冲区,如果buf长度为0则panic |
||||
CopyN |
func CopyN(dst Writer, src Reader, n int64) (written int64, err error) 拷贝N个字节,或知道遇到错误。返回拷贝的字节数和遇到的错误 |
||||
ReadAtLeast |
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) 从r读取至少min字节到buf,返回读取的字节数,如果没有读取到至少min字节数,则返回错误:
示例:
|
||||
ReadFull |
func ReadFull(r Reader, buf []byte) (n int, err error) 读取r的全部内容到buf中,返回实际读取的字节数,如果:
|
||||
WriteString |
func WriteString(w Writer, s string) (n int, err error) 将字符串s的内容写入到w中,如果w实现了WriteString方法则直接调用之,否则调用其Write一次 |
||||
ByteReader |
|
||||
ByteScanner |
|
||||
ByteWriter |
|
||||
Closer |
|
||||
LimitedReader |
该结构上定义的方法: func (l *LimitedReader) Read(p []byte) (n int, err error) |
||||
Pipe |
func Pipe() (*PipeReader, *PipeWriter) 创建一个同步的、内存中的管道,用于连接Reader和Writer 每个PipeWriter.Write调用都会阻塞,直到一个或多个PipeReader.Read了其写入的全部数据,没有内部缓冲区 并行调用Read/Write是安全的 |
||||
PipeReader |
表示管道能读的那一端。该结构上定义以下方法:
|
||||
PipeWriter |
表示管道能写的那一端。 该结构上定义以下方法:
|
||||
MultiReader |
func MultiReader(readers ...Reader) Reader 串联多个Reader,示例:
|
||||
TeeReader |
func TeeReader(r Reader, w Writer) Reader 返回一个Reader,它会把所有读取到的东西写入到一个Writer中,没有内部缓冲 |
||||
ReaderAt |
包装ReadAt函数,支持从指定的偏移量开始读取。它从底层数据源偏移量off处开始,读取最多len(p)字节到缓冲区p中 |
||||
ReaderFrom |
包装ReadFrom函数,它从r读取数据,直到EOF或者错误 |
||||
NewSectionReader |
func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader 返回一个Reader,它从off读取r,读取最多n字节 |
||||
SectionReader |
示例:
|
||||
RuneReader |
包装RuneReader函数。ReadRune读取单个UTF-8字符,返回一个rune及其长度 |
该包实现带缓冲的IO功能。执行很多碎小的写操作会影响性能,因为每次写操作都对应了系统调用,过多的系统调用会加重CPU负担。类似磁盘这样的设备,处理块对齐的数据时性能更好,因此有必要为IO提供缓冲功能。
简单的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// 实现一个仿冒Writer,它能够打印写出的字节数量 type Writer int func (*Writer) Write(p []byte) (n int, err error) { fmt.Printf("Bytes write: %v\n", len(p)) return len(p), nil } func main() { w := new(Writer) w.Write([]byte{1}) // 一字节无缓冲写出 w.Write([]byte{2}) // 创建带缓冲的Writer,缓冲区大小5字节 bw := bufio.NewWriterSize(w, 5) bw.Write([]byte{1, 2, 3}) // 不会写出,因为缓冲区没有满 bw.Write([]byte{4, 5, 6}) // 写出,输出5 fmt.Printf("Available size of buffer: %v", bw.Available()) bw.Flush() // 写出,输出1 } |
1 2 3 4 5 6 7 8 9 10 11 12 |
r := strings.NewReader("既然选择了远方,就应该风雨兼程") br := bufio.NewReaderSize(r, 18) rune, size, err := br.ReadRune() if err == nil { fmt.Printf("Character: %c, Size: %v\n", rune, size) // Character: 既, Size: 3 } buf := make([]byte, 18) br.Read(buf) fmt.Printf("String: %v", string(buf)) // String: 然选择了远 br.Discard(6) rune, _, _ = br.ReadRune() fmt.Printf("%c", rune) // 就 |
1 2 3 4 5 6 7 8 9 10 |
func main() { // 扫描器可以方便进行扫描,例如逐行读取、逐字符读取 bs := bufio.NewScanner(strings.NewReader("既然选择了远方,就应该风雨兼程")) // 每读取一个字符即停止 bs.Split(bufio.ScanRunes) for bs.Scan() { // 以字符串形式返回读取到的内容 fmt.Print(bs.Text()) } } |
包含一些工具函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// 读取全部内容 bytes, err := ioutil.ReadAll(strings.NewReader("Hello darkness my old friend")) if err == nil { fmt.Printf("%c", bytes) } // 读取目录的全部条目 infos, err := ioutil.ReadDir("/etc/mysql") for _, info := range infos { // 打印目录中的内容 fmt.Println(info.Name()) } // 读取文件的内容并返回 const FNAME = "/etc/mysql/my.cnf" content, _ := ioutil.ReadFile(FNAME) // 写入文件内容 ioutil.WriteFile(FNAME, content, 0777) // 创建临时文件和目录 dirName, _ := ioutil.TempDir("", "go") fmt.Println(dirName) // 输出目录/tmp/go154074736,注意随机后缀 |
该包提供类似C语言风格的printf、scanf
动词 | 说明 |
%v | 值的默认形式 |
%#v | 值的Go语法展现形式 |
%T | 值类型的Go语法展现形式 |
%t | true或false |
%% | 转义%且不消耗参数 |
整数格式化 | |
%b | 二进制整数 |
%c | Unicode代码点对应的字符 |
%d | 十进制 |
%o | 八进制 |
%q | 用引号包围的字符串形式,转义已经处理好 |
%x | 十六进制a-f |
%X | 十六进制A-F |
%U | Unicode格式 |
浮点数和复数 | |
%e | 科学计数法,使用e |
%E | 科学计数法,使用E |
%f %F | 小数格式,示例: fmt.Printf("%f",12.22) // 12.220000 |
%g %G | 对于大的指数使用%e %E,否则使用%f |
字符串和字节切片 | |
%s | 未解释的原始字节 |
%q | 引号包围的已经转义的字符串 |
%x %X | 十六进制表示,每个字节2字符 |
指针 | |
%p | 0x开头的十六进制 |
类型 | 格式化为 |
结构 | {field0 field1 ...} |
数组和切片 | [elem0 elem1 ...] |
映射 | map[key1:value1 key2:value2] |
上述类型的指针 | &{}, &[], &map[] |
示例 | 说明 |
%f | 默认宽度和精度 |
%9f | 宽度为9,默认精度 |
%.2f | 默认宽度,精度为2 |
%9.2f | 宽度为9,精度为2 |
%9.f | 宽度为9,精度为0 |
1 2 3 4 5 |
// 打开并得到os.File对象 f, err := os.Open("/etc/rc.local") // 关闭文件 defer f.Close() |
1 2 3 4 |
# 读取最多5字节到缓冲 b1 := make([]byte, 5) # 返回实际读取的字节数 n1, err := f.Read(b1) |
1 2 3 4 5 6 7 |
// 寻道到第6字节处,第二参数:0相对于文件头,1 相对于当前位置,2相对于文件尾 o2, err := f.Seek(6, 0) b2 := make([]byte, 2) n2, err := f.Read(b2) // Rewind f.Seek(0, 0) |
1 2 3 |
r4 := bufio.NewReader(f) // 向前偷窥 b4, err := r4.Peek(5) |
Leave a Reply