生命不止,继续Go go go.
还记得吗,我们之前介绍过ioutil包,今天继续再介绍一下bufio包吧。
从字面就看出来了,有buf,那就是缓冲的意思。
Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer object, creating another object (Reader or Writer) that also implements the interface but provides buffering and some help for textual I/O.
bufio 包实现了缓存IO。它包装了 io.Reader 和 io.Writer 对象,创建了另外的Reader和Writer对象,它们也实现了io.Reader和io.Writer接口,不过它们是有缓存的。该包同时为文本I/O提供了一些便利操作。
Reader结构
type Reader struct {
buf []byte // 缓存
rd io.Reader // 底层的io.Reader
r, w int
err error // 读过程中遇到的错误
lastByte int // 最后一次读到的字节
lastRuneSize int // 最后一次读到的Rune的大小
}
NewReaderSize
func NewReaderSize(rd io.Reader, size int) *Reader
作用:
NewReaderSize 将 rd 封装成一个带缓存的 bufio.Reader 对象,
缓存大小由 size 指定(如果小于 16 则会被设置为 16)。
如果 rd 的基类型就是有足够缓存的 bufio.Reader 类型,则直接将
rd 转换为基类型返回。
NewReader
func NewReader(rd io.Reader) *Reader
NewReader 相当于 NewReaderSize(rd, 4096)
Peek
func (b *Reader) Peek(n int) ([]byte, error)
Peek 返回缓存的一个切片,该切片引用缓存中前 n 个字节的数据,
该操作不会将数据读出,只是引用,引用的数据在下一次读取操作之
前是有效的。如果切片长度小于 n,则返回一个错误信息说明原因。
如果 n 大于缓存的总大小,则返回 ErrBufferFull。
应用
新建一个file文件,输入wangshubo1989
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
f, _ := os.Open("file")
r4 := bufio.NewReader(f)
b4, _ := r4.Peek(5)
fmt.Printf("5 bytes: %s\n", string(b4))
f.Close()
}
输出:wangs
Read
func (b *Reader) Read(p []byte) (n int, err error)
Read 从 b 中读出数据到 p 中,返回读出的字节数和遇到的错误。
如果缓存不为空,则只能读出缓存中的数据,不会从底层 io.Reader
中提取数据,如果缓存为空,则:
1、len(p) >= 缓存大小,则跳过缓存,直接从底层 io.Reader 中读出到 p 中。
2、len(p) < 缓存大小,则先将数据从底层 io.Reader 中读取到缓存
中,再从缓存读取到 p 中。
Buffered
func (b *Reader) Buffered() int
Buffered 返回缓存中未读取的数据的长度。
Discard
func (b *Reader) Discard(n int) (discarded int, err error)
Discard 跳过后续的 n 个字节的数据,返回跳过的字节数。
如果结果小于 n,将返回错误信息。
如果 n 小于缓存中的数据长度,则不会从底层提取数据。
writer结构
type Writer struct {
err error // 写过程中遇到的错误
buf []byte // 缓存
n int // 当前缓存中的字节数
wr io.Writer // 底层的 io.Writer 对象
}
NewWriterSize
func NewWriterSize(wr io.Writer, size int) *Writer
NewWriterSize 将 wr 封装成一个带缓存的 bufio.Writer 对象,
缓存大小由 size 指定(如果小于 4096 则会被设置为 4096)。
如果 wr 的基类型就是有足够缓存的 bufio.Writer 类型,则直接将
wr 转换为基类型返回。
NewWriter
func NewWriter(wr io.Writer) *Writer
NewWriter 相当于 NewWriterSize(wr, 4096)
WriteString
func (b *Writer) WriteString(s string) (int, error)
WriteString 功能同 Write,只不过写入的是字符串
WriteRune
func (b *Writer) WriteRune(r rune) (size int, err error)
WriteRune 向 b 写入 r 的 UTF-8 编码,返回 r 的编码长度。
Flush
func (b *Writer) Flush() error
Flush 将缓存中的数据提交到底层的 io.Writer 中
Available
func (b *Writer) Available() int
Available 返回缓存中未使用的空间的长度
Buffered
func (b *Writer) Buffered() int
Buffered 返回缓存中未提交的数据的长度
Reset
func (b *Writer) Reset(w io.Writer)
Reset 将 b 的底层 Writer 重新指定为 w,同时丢弃缓存中的所有数据,复位
所有标记和错误信息。相当于创建了一个新的 bufio.Writer。
应用
// Writing files in Go follows similar patterns to the
// ones we saw earlier for reading.
package main
import (
"bufio"
"fmt"
"io/ioutil"
"os"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
// To start, here's how to dump a string (or just
// bytes) into a file.
d1 := []byte("hello\ngo\n")
err := ioutil.WriteFile("/tmp/dat1", d1, 0644)
check(err)
// For more granular writes, open a file for writing.
f, err := os.Create("/tmp/dat2")
check(err)
// It's idiomatic to defer a `Close` immediately
// after opening a file.
defer f.Close()
// You can `Write` byte slices as you'd expect.
d2 := []byte{115, 111, 109, 101, 10}
n2, err := f.Write(d2)
check(err)
fmt.Printf("wrote %d bytes\n", n2)
// A `WriteString` is also available.
n3, err := f.WriteString("writes\n")
fmt.Printf("wrote %d bytes\n", n3)
// Issue a `Sync` to flush writes to stable storage.
f.Sync()
// `bufio` provides buffered writers in addition
// to the buffered readers we saw earlier.
w := bufio.NewWriter(f)
n4, err := w.WriteString("buffered\n")
fmt.Printf("wrote %d bytes\n", n4)
// Use `Flush` to ensure all buffered operations have
// been applied to the underlying writer.
w.Flush()
}
这个应该算是go中的特色了吧,反正对于c++过来的人说挺特别的。
在 bufio 包中有多种方式获取文本输入,ReadBytes、ReadString 和独特的 ReadLine,对于简单的目的这些都有些过于复杂了。在 Go 1.1 中,添加了一个新类型,Scanner,以便更容易的处理如按行读取输入序列或空格分隔的词等,这类简单的任务。它终结了如输入一个很长的有问题的行这样的输入错误,并且提供了简单的默认行为:基于行的输入,每行都剔除分隔标识。
应用
// A _line filter_ is a common type of program that reads
// input on stdin, processes it, and then prints some
// derived result to stdout. `grep` and `sed` are common
// line filters.
// Here's an example line filter in Go that writes a
// capitalized version of all input text. You can use this
// pattern to write your own Go line filters.
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
// Wrapping the unbuffered `os.Stdin` with a buffered
// scanner gives us a convenient `Scan` method that
// advances the scanner to the next token; which is
// the next line in the default scanner.
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
// `Text` returns the current token, here the next line,
// from the input.
ucl := strings.ToUpper(scanner.Text())
// Write out the uppercased line.
fmt.Println(ucl)
}
// Check for errors during `Scan`. End of file is
// expected and not reported by `Scan` as an error.
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}
}
运行结果:
wangshubo1989
WANGSHUBO1989