学习bufio、fmt



// "GHI "
}


------------------------------------------------------------


// ReadLine 是一个低级的原始的行读取操作
// 大多数情况下,应该使用 ReadBytes('\n') 或 ReadString('\n')
// 或者使用一个 Scanner
//
// ReadLine 通过调用 ReadSlice 方法实现,返回的也是缓存的切片
// ReadLine 尝试返回一个单行数据,不包括行尾标记(\n 或 \r\n)
// 如果在缓存中找不到行尾标记,则设置 isPrefix 为 true,表示查找未完成
// 同时读出缓存中的数据并作为切片返回
// 只有在当前缓存中找到行尾标记,才将 isPrefix 设置为 false,表示查找完成
// 可以多次调用 ReadLine 来读出一行
// 返回的数据在下一次读取操作之前是有效的
// 如果 ReadLine 无法获取任何数据,则返回一个错误信息(通常是 io.EOF)
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)


func main() {
s := strings.NewReader("ABC\nDEF\r\nGHI\r\nJKL")
br := bufio.NewReader(s)


w, isPrefix, _ := br.ReadLine()
fmt.Printf("%q %v\n", w, isPrefix)
// "ABC" false


w, isPrefix, _ = br.ReadLine()
fmt.Printf("%q %v\n", w, isPrefix)
// "DEF" false


w, isPrefix, _ = br.ReadLine()
fmt.Printf("%q %v\n", w, isPrefix)
// "GHI" false
}


------------------------------------------------------------


// ReadBytes 在 b 中查找 delim 并读出 delim 及其之前的所有数据
// 如果 ReadBytes 在找到 delim 之前遇到错误
// 则返回遇到错误之前的所有数据,同时返回遇到的错误(通常是 io.EOF)
// 只有当 ReadBytes 找不到 delim 时,err 才不为 nil
// 对于简单的用途,使用 Scanner 可能更方便
func (b *Reader) ReadBytes(delim byte) (line []byte, err error)


func main() {
s := strings.NewReader("ABC DEF GHI JKL")
br := bufio.NewReader(s)


w, _ := br.ReadBytes(' ')
fmt.Printf("%q\n", w)
// "ABC "


w, _ = br.ReadBytes(' ')
fmt.Printf("%q\n", w)
// "DEF "


w, _ = br.ReadBytes(' ')
fmt.Printf("%q\n", w)
// "GHI "
}


------------------------------------------------------------


// ReadString 功能同 ReadBytes,只不过返回的是一个字符串
func (b *Reader) ReadString(delim byte) (line string, err error)


func main() {
s := strings.NewReader("ABC DEF GHI JKL")
br := bufio.NewReader(s)


w, _ := br.ReadString(' ')
fmt.Printf("%q\n", w)
// "ABC "


w, _ = br.ReadString(' ')
fmt.Printf("%q\n", w)
// "DEF "


w, _ = br.ReadString(' ')
fmt.Printf("%q\n", w)
// "GHI "
}


------------------------------------------------------------


// WriteTo 实现了 io.WriterTo 接口
func (b *Reader) WriteTo(w io.Writer) (n int64, err error)


func main() {
s := strings.NewReader("ABCEFG")
br := bufio.NewReader(s)
b := bytes.NewBuffer(make([]byte, 0))


br.WriteTo(b)
fmt.Printf("%s\n", b)
// ABCEFG
}


------------------------------------------------------------


// Writer 实现了带缓存的 io.Writer 对象
// 如果在向 Writer 中写入数据的过程中遇到错误
// 则 Writer 不会再接受任何数据
// 而且后续的写入操作都将返回错误信息
type Writer struct {
// 私有字段
}


// NewWriterSize 将 wr 封装成一个拥有 size 大小缓存的 bufio.Writer 对象
// 如果 wr 的基类型就是 bufio.Writer 类型,而且拥有足够的缓存
// 则直接将 wr 转换为基类型并返回
func NewWriterSize(wr io.Writer, size int) *Writer


// NewWriter 相当于 NewWriterSize(wr, 4096)
func NewWriter(wr io.Writer) *Writer


------------------------------------------------------------


// Flush 将缓存中的数据提交到底层的 io.Writer 中
func (b *Writer) Flush() error


// Available 返回缓存中的可以空间
func (b *Writer) Available() int


// Buffered 返回缓存中未提交的数据长度
func (b *Writer) Buffered() int


// Write 将 p 中的数据写入 b 中,返回写入的字节数
// 如果写入的字节数小于 p 的长度,则返回一个错误信息
func (b *Writer) Write(p []byte) (nn int, err error)


// WriteString 同 Write,只不过写入的是字符串
func (b *Writer) WriteString(s string) (int, error)


func main() {
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
fmt.Println(bw.Available()) // 4096
fmt.Println(bw.Buffered())  // 0


bw.WriteString("ABCDEFGH")
fmt.Println(bw.Available()) // 4088
fmt.Println(bw.Buffered())  // 8
fmt.Printf("%q\n", b)       // ""


bw.Flush()
fmt.Println(bw.Available()) // 4096
fmt.Println(bw.Buffered())  // 0
fmt.Printf("%q\n", b)       // "ABCEFG"
}


------------------------------------------------------------


// WriteByte 向 b 中写入一个字节
func (b *Writer) WriteByte(c byte) error


// WriteRune 向 b 中写入 r 的 UTF8 编码
// 返回 r 的编码长度
func (b *Writer) WriteRune(r rune) (size int, err error)


func main() {
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
bw.WriteByte('H')
bw.WriteByte('e')
bw.WriteByte('l')
bw.WriteByte('l')
bw.WriteByte('o')
bw.WriteByte(' ')
bw.WriteRune('世')
bw.WriteRune('界')
bw.WriteRune('!')
bw.Flush()
fmt.Println(b) // Hello 世界!
}


------------------------------------------------------------


// ReadFrom 实现了 io.ReaderFrom 接口
func (b *Writer) ReadFrom(r io.Reader) (n int64, err error)


func main() {
b := bytes.NewBuffer(make([]byte, 0))
s := strings.NewReader("Hello 世界!")
bw := bufio.NewWriter(b)
bw.ReadFrom(s)
bw.Flush()
fmt.Println(b) // Hello 世界!
}


------------------------------------------------------------


// ReadWriter 集成了 bufio.Reader 和 bufio.Writer
// 它实现了 io.ReadWriter 接口
type ReadWriter struct {
*Reader
*Writer
}


// NewReadWriter 封装 r 和 w 为一个 bufio.ReadWriter 对象
func NewReadWriter(r *Reader, w *Writer) *ReadWriter


------------------------------------------------------------


// scan.go


------------------------------------------------------------


// Scanner 提供了一个方便的接口来读取数据,例如读取一个多行文本
// 连续调用 Scan 方法将扫描数据中的“指定部分”,跳过各个“指定部分”之间的数据
// Scanner 使用了缓存,所以“指定部分”的长度不能超出缓存的长度
// Scanner 需要一个 SplitFunc 类型的“切分函数”来确定“指定部分”的格式
// 本包中提供的“切分函数”有“行切分函数”、“字节切分函数”、“UTF8字符编码切分函数”
// 和“单词切分函数”,用户也可以自定义“切分函数”
// 默认的“切分函数”为“行切分函数”,用于获取数据中的一行数据(不包括行尾符)
//
// 扫描在遇到下面的情况时会停止:
// 1、数据扫描完毕,遇到 io.EOF
// 2、遇到读写错误
// 3、“指定部分”的长度超过了缓存的长度
// 如果要对数据进行更多的控制,比如的错误处理或扫描更大的“指定部分”或顺序扫描
// 则应该使用 bufio.Reader
type Scanner struct {
// 私有字段
}


// SplitFunc 用来定义“切分函数”类型
// data 是要扫描的数据
// atEOF 标记底层 io.Reader 中的数据是否已经读完
// advance 返回 data 中已处理的数据长度
// token 返回找到的“指定部分”
// err 返回错误信息
// 如果在 data 中无法找到一个完整的“指定部分”
// 则 SplitFunc 返回 (0, nil) 来告诉 Scanner
// 向缓存中填充更多数据,然后再次扫描
//
// 如果返回的 err 是非 nil 值,扫描将被终止,并返回错误信息
//
// 如果 data 为空,则“切分函数”将不被调用
// 意思是在 SplitFunc 中不必考虑 data 为空的情况
//
// SplitFunc 的作用很简单,从 data 中找出你感兴趣的数据,然后返回
// 并告诉调用者,data 中有多少数据你已经处理过了
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)


// NewScanner 创建一个 Scanner 来扫描 r
// 默认切分函数为 ScanLines
func NewScanner(r io.Reader) *Scanner


// Err 返回扫描过程中遇到的非 EOF 错误
// 供用户调用,以便获取错误信息
func (s *Scanner) Err() error


------------------------------------------------------------


// Bytes 将最后一次扫描出的“指定部分”作为一个切片返回(引用传递)
// 下一次的 Scan 操作会覆盖本次返回的结果
func (s *Scanner) Bytes() []byte


// Text 将最后一次扫描出的“指定部分”作为字符串返回(值传递)
func (s *Scanner) Text() string


------------------------------------------------------------


// Scan 在 Scanner 的数据中扫描“指定部分”
// 找到后,用户可以通过 Bytes 或 Text 方法来取出“指定部分”
// 如果扫描过程中遇到错误,则终止扫描,并返回 false
func (s *Scanner) Scan() bool


func main() {
s := strings.NewReader("ABC\nDEF\r\nGHI\nJKL")
bs := bufio.NewScanner(s)
for bs.Scan() {
fmt.Printf("%s %v\n", bs.Bytes(), bs.Text())
}
// ABC ABC
// DEF DEF
// GHI GHI
// JKL JKL
}


------------------------------------------------------------


// Split 用于设置 Scanner 的“切分函数”
// 这个函数必须在调用 Scan 前执行
func (s *Scanner) Split(split SplitFunc)


func main() {
s := strings.NewReader("ABC DEF GHI JKL")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanWords)
for bs.Scan() {
fmt.Println(bs.Text())
}
// ABC
// DEF
// GHI
// JKL
}


------------------------------------------------------------


// ScanBytes 是一个“切分函数”
// 用来找出 data 中的单个字节并返回
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error)


func main() {
s := strings.NewReader("Hello 世界!")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanBytes)
for bs.Scan() {
fmt.Printf("%s ", bs.Text())
}
}


------------------------------------------------------------


// ScanRunes 是一个“切分函数”
// 用来找出 data 中的单个 UTF8 字符的编码并返回
// 如果 UTF8 解码出错,则返回的 U+FFFD 会被做为 "\xef\xbf\xbd" 返回
// 这使得用户无法区分“真正的U+FFFD字符”和“解码错误的返回值”
func ScanRunes(data []byte, atEOF bool) (advance int, token []byte, err error)


func main() {
s := strings.NewReader("Hello 世界!")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanRunes)
for bs.Scan() {
fmt.Printf("%s ", bs.Text())
} // H e l l o   世 界 !
}


------------------------------------------------------------


// ScanLines 是一个“切分函数”
// 用来找出 data 中的单行数据并返回(包括空行)
// 行尾标记可能是 \n 或 \r\n(返回值不包括行尾标记)
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error)


------------------------------------------------------------


// ScanWords 是一个“切分函数”
// 用来找出 data 中的单词
// 单词以空白字符分隔,空白字符由 unicode.IsSpace 定义

func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error)


// format.go


------------------------------------------------------------


// Fprintf 将参数列表 a 填写到格式字符串 format 的占位符中
// 并将填写后的结果写入 w 中,返回写入的字节数
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)


// Printf 将参数列表 a 填写到格式字符串 format 的占位符中
// 并将填写后的结果写入 os.Stdout 中,返回写入的字节数
func Printf(format string, a ...interface{}) (n int, err error)


// Sprintf 将参数列表 a 填写到格式字符串 format 的占位符中
// 返回填写后的结果
func Sprintf(format string, a ...interface{}) string


// Errorf 将参数列表 a 填写到格式字符串 format 的占位符中
// 并将填写后的结果转换为 error 类型返回
func Errorf(format string, a ...interface{}) error


------------------------------------------------------------


// Fprint 将参数列表 a 中的各个参数转换为字符串格式并写入到 w 中
// 各个参数之间以空格分隔,返回写入的字节数
func Fprint(w io.Writer, a ...interface{}) (n int, err error)


// Print 将参数列表 a 中的各个参数转换为字符串格式并写入到 os.Stdout 中
// 各个参数之间以空格分隔,返回写入的字节数
func Print(a ...interface{}) (n int, err error)


// Sprint 将参数列表 a 中的各个参数转换为字符串格式并返回
// 各个参数之间以空格分隔
func Sprint(a ...interface{}) string


------------------------------------------------------------


// Fprintln 在 Fprint 的基础上,再向 w 中写入一个换行符
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)


// Println 在 Print 的基础上,再向 os.Stdout 中写入一个换行符
func Println(a ...interface{}) (n int, err error)


// Sprintln 在 Sprint 的基础上,在返回值的最后添加一个换行符
func Sprintln(a ...interface{}) string


------------------------------------------------------------


// 示例
func main() {
fmt.Fprintf(os.Stdout, "%08b\n", 32) // 00100000
fmt.Printf("%08b\n", 32)             // 00100000
fmt.Print(fmt.Sprintf("%08b\n", 32)) // 00100000
fmt.Print(fmt.Errorf("%08b\n", 32))  // 00100000


fmt.Fprint(os.Stdout, "A")
fmt.Print("B")
fmt.Print(fmt.Sprint("C"))
// ABC


fmt.Print("\n")


fmt.Fprintln(os.Stdout, "A") // A
fmt.Println("B")             // B
fmt.Print(fmt.Sprintln("C")) // C
}


------------------------------------------------------------


// Formatter 用于实现对象的自定义格式输出
type Formatter interface {
// Format 用来处理当对象遇到 c 标记时的输出方式(c 相当于 %s 中的 s)
// f 用来获取占位符的宽度、精度、扩展标记等信息,同时实现最终的输出
// c 是要处理的标记
Format(f State, c rune)
}


// State 用来获取占位符的状态,包括宽度、精度、扩展标记等信息
// 同时实现格式化后的字符串的输出
type State interface {
// Write 用于将格式化后的字符串输出到指定的对象
// 根据 Print 函数(Fprintf,Printf,Sprintf)的不同,输出到不同的地方
Write(b []byte) (ret int, err error)
// Width 返回占位符的宽度值(wid)和宽度是否被设置(ok)
Width() (wid int, ok bool)
// Precision 返回占位符的精度值(prec)和精度是否被设置(ok)
Precision() (prec int, ok bool)
// Flag 返回扩展标记 c(一个字符,比如 %#s 中的 #)是否已被设置
Flag(c int) bool
}


type Stringer interface {
// String 获取对象的文本形式
String() string
}


type GoStringer interface {
// GoString 获取对象的 Go 语法文本形式(以 %#v 格式输出的文本)
GoString() string
}


------------------------------------------------------------


// 示例
type Ustr string


func (us Ustr) String() string {
return string(us) + " 自定义格式"
}


func (us Ustr) GoString() string {
return string(us) + " Go 格式"
}


func (us Ustr) Format(f fmt.State, c rune) {
switch c {
case 'm', 'M':
f.Write([]byte(us + "\n扩展标记:["))
if f.Flag('-') {
f.Write([]byte(" -"))
}
if f.Flag('+') {
f.Write([]byte(" +"))
}
if f.Flag('#') {
f.Write([]byte(" #"))
}
if f.Flag(' ') {
f.Write([]byte(" space"))
}
if f.Flag('0') {
f.Write([]byte(" 0"))
}
f.Write([]byte(" ]\n"))
if w, wok := f.Width(); wok {
f.Write([]byte("宽度值:" + fmt.Sprint(w) + "\n"))
}
if p, pok := f.Precision(); pok {
f.Write([]byte("精度值:" + fmt.Sprint(p)))
}
case 'v': // 如果使用 Format 函数,则必须自己处理所有格式,包括 %#v
if f.Flag('#') {
f.Write([]byte(us.GoString()))
} else {
f.Write([]byte(us.String()))
}
default: // 如果使用 Format 函数,则必须自己处理默认输出
f.Write([]byte(us.String()))
}
}


func main() {
us := Ustr("Hello World!")
fmt.Printf("% 0-+#8.5m\n", us)
// Hello World!
// 扩展标记:[ - + # space 0 ]
// 宽度值:8
// 精度值:5
fmt.Println(us)
// Hello World! 自定义格式
fmt.Printf("%#v\n", us)
// Hello World! Go 格式
}






============================================================






// scan.go


------------------------------------------------------------


// Fscanf 用于扫描 r 中的数据,并根据 format 指定的格式
// 将扫描出的数据填写到参数列表 a 中
// 当 r 中的数据被全部扫描完毕或扫描长度超出 format 指定的长度时
// 则停止扫描(换行符会被当作空格处理)
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error)


func main() {
s := strings.NewReader("我的名字叫 Golang ,今年 4 岁")
var name string
var age int
// 注意:这里必须传递指针 &name, &age
// 要获取的数据前后必须有空格
fmt.Fscanf(s, "我的名字叫 %s ,今年 %d 岁", &name, &age)
fmt.Printf("%s  %d", name, age)
// Golang  4
}


// Scanf 用于扫描 os.Stdin 中的数据,并根据 format 指定的格式
// 将扫描出的数据填写到参数列表 a 中
// 当 r 中的数据被全部扫描完毕或者扫描长度超出 format 指定的长度时
// 则停止扫描(换行符会被当作空格处理)
func Scanf(format string, a ...interface{}) (n int, err error)


func main() {
var name string
var age int
// 注意:这里必须传递指针 &name, &age
// 要获取的数据前后必须有空格
fmt.Scanf("%s %d", &name, &age)
// 在控制台输入:Golang 4
fmt.Printf("我的名字叫 %s ,今年 %d 岁", name, age)
// 我的名字叫 Golang ,今年 4 岁
}


// Sscanf 用于扫描 str 中的数据,并根据 format 指定的格式
// 将扫描出的数据填写到参数列表 a 中
// 当 r 中的数据被全部扫描完毕或者扫描长度超出 format 指定的长度时
// 则停止扫描(换行符会被当作空格处理)
func Sscanf(str string, format string, a ...interface{}) (n int, err error)


func main() {
s := "我的名字叫 Golang ,今年 4 岁"
var name string
var age int
// 注意:这里必须传递指针 &name, &age
// 要获取的数据前后必须有空格
fmt.Sscanf(s, "我的名字叫 %s ,今年 %d 岁", &name, &age)
fmt.Printf("%s  %d", name, age)
// Golang  4
}


------------------------------------------------------------


// Fscan 用于扫描 r 中的数据,并将数据以空格为分割符进行分割
// 然后填写到参数列表 a 中
// 当 r 中的数据被全部扫描完毕或者参数列表 a 被全部填写完毕
// 则停止扫描(换行符会被当作空格处理)
func Fscan(r io.Reader, a ...interface{}) (n int, err error)


// Scan 用于扫描 os.Stdin 中的数据,并将数据以空格为分割符进行分割
// 然后填写到参数列表 a 中
// 当 r 中的数据被全部扫描完毕或者参数列表 a 被全部填写完毕
// 则停止扫描(换行符会被当作空格处理)
func Scan(a ...interface{}) (n int, err error)


// Sscan 用于扫描 str 中的数据,并将数据以空格为分割符进行分割
// 然后填写到参数列表 a 中
// 当 r 中的数据被全部扫描完毕或者参数列表 a 被全部填写完毕
// 则停止扫描(换行符会被当作空格处理)
func Sscan(str string, a ...interface{}) (n int, err error)


------------------------------------------------------------


// Fscanln 用于扫描 r 中的数据,并将数据以空格为分割符进行分割
// 然后填写到参数列表 a 中
// 当扫描过程中遇到 '\n' 或者参数列表 a 被全部填写完毕
// 则停止扫描
func Fscanln(r io.Reader, a ...interface{}) (n int, err error)


// Scanln 用于扫描 os.Stdin 中的数据,并将数据以空格为分割符进行分割
// 然后填写到参数列表 a 中
// 当扫描过程中遇到 '\n' 或者参数列表 a 被全部填写完毕
// 则停止扫描
func Scanln(a ...interface{}) (n int, err error)


// Sscanln 用于扫描 str 中的数据,并将数据以空格为分割符进行分割
// 然后填写到参数列表 a 中
// 当扫描过程中遇到 '\n' 或者参数列表 a 被全部填写完毕
// 则停止扫描
func Sscanln(str string, a ...interface{}) (n int, err error)


------------------------------------------------------------


// ScanState 会返回扫描状态给自定义的 Scanner
// Scanner 可能会做字符的实时扫描
// 或者通过 ScanState 获取以空格分割的 token
type ScanState interface {
// ReadRune 从输入对象中读出一个 Unicode 字符
// 如果在 Scanln、Fscanln 或 Sscanln 中调用该方法
// 该方法会在遇到 '\n' 或读取超过指定的宽度时返回 EOF
ReadRune() (r rune, size int, err error)
// UnreadRune 撤消最后一次的 ReadRune 操作
UnreadRune() error
// SkipSpace 跳过输入数据中的空格
// 在 Scanln、Fscanln、Sscanln 操作中,换行符会被当作 EOF
// 在其它 Scan 操作中,换行符会被当作空格
SkipSpace()
// 如果参数 skipSpace 为 true,则 Token 会跳过输入数据中的空格
// 然后返回满足函数 f 的连续字符,如果 f 为 nil,则使用 !unicode.IsSpace 来代替 f
// 在 Scanln、Fscanln、Sscanln 操作中,换行符会被当作 EOF
// 在其它 Scan 操作中,换行符会被当作空格
// 返回的 token 是一个切片,返回的数据可能在下一次调用 Token 的时候被修改
Token(skipSpace bool, f func(rune) bool) (token []byte, err error)
// Width 返回宽度值以及宽度值是否被设置
Width() (wid int, ok bool)
// 因为 ReadRune 已经通过接口实现,所以 Read 可能永远不会被 Scan 例程调用
// 一个 ScanState 的实现,可能会选择废弃 Read 方法,而使其始终返回一个错误信息
Read(buf []byte) (n int, err error)
}


// Scanner 用于实现对象的自定义格式扫描
type Scanner interface {
// Scan 用来处理当对象遇到 c 标记时的扫描方式(c 相当于 %s 中的 s)
// state 用来处理扫描状态
// c 是要处理的标记
Scan(state ScanState, verb rune) error
}

你可能感兴趣的:(学习bufio、fmt)