bufio

 1 package main
 2 
 3 import (
 4     "bufio"
 5     "fmt"
 6     "os"
 7 )
 8 
 9 func main() {
10     w := bufio.NewWriter(os.Stdout)
11     fmt.Fprint(w, "Hello, ")
12     fmt.Fprint(w, "world!")
13     w.Flush() // Don't forget to flush!
14 }
 1 package main
 2 
 3 import (
 4     "bufio"
 5     "fmt"
 6     "strconv"
 7     "strings"
 8 )
 9 
10 func main() {
11     // An artificial input source.
12     const input = "1234 5678 1234567901234567890"
13     scanner := bufio.NewScanner(strings.NewReader(input))
14     // Create a custom split function by wrapping the existing ScanWords function.
15     split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
16         advance, token, err = bufio.ScanWords(data, atEOF)
17         if err == nil && token != nil {
18             _, err = strconv.ParseInt(string(token), 10, 32)
19         }
20         return
21     }
22     // Set the split function for the scanning operation.
23     scanner.Split(split)
24     // Validate the input
25     for scanner.Scan() {
26         fmt.Printf("%s\n", scanner.Text())
27     }
28     if err := scanner.Err(); err != nil {
29         fmt.Printf("Invalid input: %s", err)
30     }
31 }
 1 package main
 2 
 3 import (
 4     "bufio"
 5     "fmt"
 6     "os"
 7 )
 8 
 9 func main() {
10     scanner := bufio.NewScanner(os.Stdin)
11     for scanner.Scan() {
12         fmt.Println("input: ", scanner.Text())
13     }
14     if err := scanner.Err(); err != nil {
15         fmt.Fprintln(os.Stderr, "reading standard input: ", err)
16     }
17 }
 1 package main
 2 
 3 import (
 4     "bufio"
 5     "fmt"
 6     "os"
 7     "strings"
 8 )
 9 
10 func main() {
11     // An artificial input source.
12     const input = "Now is the winter of our discontent,\nMade glorious summer by this sun of York.\n"
13     scanner := bufio.NewScanner(strings.NewReader(input))
14     // Set the split function for the scanning operation.
15     scanner.Split(bufio.ScanWords)
16     // Count the words.
17     count := 0
18     for scanner.Scan() {
19         count++
20     }
21     if err := scanner.Err(); err != nil {
22         fmt.Fprintln(os.Stderr, "reading input:", err)
23     }
24     fmt.Printf("%d\n", count)
25 }

 bufio.Reader

 1 package main
 2 
 3 import (
 4     "bufio"
 5     "fmt"
 6     "strings"
 7 )
 8 
 9 func main() {
10     sr := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
11     buf := bufio.NewReaderSize(sr, 0)
12     b := make([]byte, 10)
13 
14     fmt.Println(buf.Buffered()) // 0
15     s, _ := buf.Peek(5)
16     /*
17     // Peek 返回缓存的一个切片,该切片引用缓存中前 n 个字节的数据,
18     // 该操作不会将数据读出,只是引用,引用的数据在下一次读取操作之
19     // 前是有效的。如果切片长度小于 n,则返回一个错误信息说明原因。
20     // 如果 n 大于缓存的总大小,则返回 ErrBufferFull。
21     func (b *Reader) Peek(n int) ([]byte, error)
22     */
23     s[0], s[1], s[2] = 'a', 'b', 'c'
24     fmt.Printf("%d   %q\n", buf.Buffered(), s) // 16   "abcDE"
25 
26     buf.Discard(1)
27     /*
28     // Discard 跳过后续的 n 个字节的数据,返回跳过的字节数。
29     // 如果结果小于 n,将返回错误信息。
30     // 如果 n 小于缓存中的数据长度,则不会从底层提取数据。
31     func (b *Reader) Discard(n int) (discarded int, err error)
32     */
33     for n, err := 0, error(nil); err == nil; {
34         n, err = buf.Read(b)
35         fmt.Printf("%d   %q   %v\n", buf.Buffered(), b[:n], err)
36     }
37 }

 

 1 package main
 2 
 3 import (
 4     "bufio"
 5     "fmt"
 6     "strings"
 7 )
 8 
 9 // 示例:ReadLine
10 func main() {
11     sr := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ\n1234567890")
12     buf := bufio.NewReaderSize(sr, 0)
13 
14     for line, isPrefix, err := []byte{0}, false, error(nil); len(line) > 0 && err == nil; {
15         line, isPrefix, err = buf.ReadLine()
16         fmt.Printf("%q   %t   %v\n", line, isPrefix, err)
17     }
18     // "ABCDEFGHIJKLMNOP"   true   <nil>
19     // "QRSTUVWXYZ"   false   <nil>
20     // "1234567890"   false   <nil>
21     // ""   false   EOF
22 
23     fmt.Println("----------")
24 
25     // 尾部有一个换行标记
26     buf = bufio.NewReaderSize(strings.NewReader("ABCDEFG\n"), 0)
27 
28     for line, isPrefix, err := []byte{0}, false, error(nil); len(line) > 0 && err == nil; {
29         line, isPrefix, err = buf.ReadLine()
30         fmt.Printf("%q   %t   %v\n", line, isPrefix, err)
31     }
32     // "ABCDEFG"   false   <nil>
33     // ""   false   EOF
34 
35     fmt.Println("----------")
36 
37     // 尾部没有换行标记
38     buf = bufio.NewReaderSize(strings.NewReader("ABCDEFG"), 0)
39 
40     for line, isPrefix, err := []byte{0}, false, error(nil); len(line) > 0 && err == nil; {
41         line, isPrefix, err = buf.ReadLine()
42         fmt.Printf("%q   %t   %v\n", line, isPrefix, err)
43     }
44     // "ABCDEFG"   false   <nil>
45     // ""   false   EOF
46 }

 

 1 package main
 2 
 3 import (
 4     "bufio"
 5     "fmt"
 6     "strings"
 7 )
 8 
 9 // ReadSlice 在 b 中查找 delim 并返回 delim 及其之前的所有数据。
10 // 该操作会读出数据,返回的切片是已读出的数据的引用,切片中的数据
11 // 在下一次读取操作之前是有效的。
12 //
13 // 如果找到 delim,则返回查找结果,err 返回 nil。
14 // 如果未找到 delim,则:
15 // 1、缓存不满,则将缓存填满后再次查找。
16 // 2、缓存是满的,则返回整个缓存,err 返回 ErrBufferFull。
17 //
18 // 如果未找到 delim 且遇到错误(通常是 io.EOF),则返回缓存中的所
19 // 有数据和遇到的错误。
20 //
21 // 因为返回的数据有可能被下一次的读写操作修改,所以大多数操作应该
22 // 使用 ReadBytes 或 ReadString,它们返回的是数据的拷贝。
23 //func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
24 
25 // 示例:ReadSlice
26 func main() {
27     // 尾部有换行标记
28     buf := bufio.NewReaderSize(strings.NewReader("ABCDEFG\n"), 0)
29 
30     for line, err := []byte{0}, error(nil); len(line) > 0 && err == nil; {
31         line, err = buf.ReadSlice('\n')
32         fmt.Printf("%q   %v\n", line, err)
33     }
34     // "ABCDEFG\n"   <nil>
35     // ""   EOF
36 
37     fmt.Println("----------")
38 
39     // 尾部没有换行标记
40     buf = bufio.NewReaderSize(strings.NewReader("ABCDEFG"), 0)
41 
42     for line, err := []byte{0}, error(nil); len(line) > 0 && err == nil; {
43         line, err = buf.ReadSlice('\n')
44         fmt.Printf("%q   %v\n", line, err)
45     }
46     // "ABCDEFG"   EOF
47 }

 bufio.Writer

 1 package main
 2 
 3 import (
 4     "bufio"
 5     "fmt"
 6     "os"
 7 )
 8 
 9 func main() {
10     buf := bufio.NewWriterSize(os.Stdout, 0)
11     fmt.Println(buf.Available(), buf.Buffered()) // 4096 0
12 
13     buf.WriteString("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
14     fmt.Println(buf.Available(), buf.Buffered()) // 4070 26
15 
16     // 缓存后统一输出,避免终端频繁刷新,影响速度
17     buf.Flush() // ABCDEFGHIJKLMNOPQRSTUVWXYZ
18 }

bufio.ReaderWriter

// 顾名思义: bufio.ReaderWriter综合了Reader和Writer两者的功能
// ReadWriter 集成了 bufio.Reader 和 bufio.Writer
type ReadWriter struct {
    *Reader
    *Writer
}

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

bufio.Scanner

  1 // 主要用于指定匹配函数,进行文本扫描,返回匹配结果
  2 // 自定义匹配函数中,支持正则表达式进行匹配
  3 // Scanner 提供了一个方便的接口来读取数据,例如遍历多行文本中的行。Scan 方法会通过
  4 // 一个“匹配函数”读取数据中符合要求的部分,跳过不符合要求的部分。“匹配函数”由调
  5 // 用者指定。本包中提供的匹配函数有“行匹配函数”、“字节匹配函数”、“字符匹配函数”
  6 // 和“单词匹配函数”,用户也可以自定义“匹配函数”。默认的“匹配函数”为“行匹配函
  7 // 数”,用于获取数据中的一行内容(不包括行尾标记)
  8 //
  9 // Scanner 使用了缓存,所以匹配部分的长度不能超出缓存的容量。默认缓存容量为 4096 -
 10 // bufio.MaxScanTokenSize,用户可以通过 Buffer 方法指定自定义缓存及其最大容量。
 11 //
 12 // Scan 在遇到下面的情况时会终止扫描并返回 false(扫描一旦终止,将无法再继续):
 13 // 1、遇到 io.EOF
 14 // 2、遇到读写错误
 15 // 3、“匹配部分”的长度超过了缓存的长度
 16 //
 17 // 如果需要对错误进行更多的控制,或“匹配部分”超出缓存容量,或需要连续扫描,则应该
 18 // 使用 bufio.Reader
 19 type Scanner struct { ... }
 20 
 21 // NewScanner 创建一个 Scanner 来扫描 r,默认匹配函数为 ScanLines。
 22 func NewScanner(r io.Reader) *Scanner
 23 
 24 // Buffer 用于设置自定义缓存及其可扩展范围,如果 max 小于 len(buf),则 buf 的尺寸将
 25 // 固定不可调。Buffer 必须在第一次 Scan 之前设置,否则会引发 panic。
 26 // 默认情况下,Scanner 会使用一个 4096 - bufio.MaxScanTokenSize 大小的内部缓存。
 27 func (s *Scanner) Buffer(buf []byte, max int)
 28 
 29 // Split 用于设置“匹配函数”,这个函数必须在调用 Scan 前执行。
 30 func (s *Scanner) Split(split SplitFunc)
 31 
 32 // SplitFunc 用来定义“匹配函数”,data 是缓存中的数据。atEOF 标记数据是否读完。
 33 // advance 返回 data 中已处理的数据的长度。token 返回找到的“匹配部分”,“匹配
 34 // 部分”可以是缓存的切片,也可以是自己新建的数据(比如 bufio.errorRune)。“匹
 35 // 配部分”将在 Scan 之后通过 Bytes 和 Text 反馈给用户。err 返回错误信息。
 36 //
 37 // 如果在 data 中无法找到一个完整的“匹配部分”则应返回 (0, nil, nil),以便告诉
 38 // Scanner 向缓存中填充更多数据,然后再次扫描(Scan 会自动重新扫描)。如果缓存已
 39 // 经达到最大容量还没有找到,则 Scan 会终止并返回 false。
 40 // 如果 data 为空,则“匹配函数”将不会被调用,意思是在“匹配函数”中不必考虑
 41 // data 为空的情况。
 42 //
 43 // 如果 err != nil,扫描将终止,如果 err == ErrFinalToken,则 Scan 将返回 true,
 44 // 表示扫描正常结束,如果 err 是其它错误,则 Scan 将返回 false,表示扫描出错。错误
 45 // 信息可以在 Scan 之后通过 Err 方法获取。
 46 //
 47 // SplitFunc 的作用很简单,从 data 中找出你感兴趣的数据,然后返回,同时返回已经处理
 48 // 的数据的长度。
 49 type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)
 50 
 51 // Scan 开始一次扫描过程,如果匹配成功,可以通过 Bytes() 或 Text() 方法取出结果,
 52 // 如果遇到错误,则终止扫描,并返回 false。
 53 func (s *Scanner) Scan() bool
 54 
 55 // Bytes 将最后一次扫描出的“匹配部分”作为一个切片引用返回,下一次的 Scan 操作会覆
 56 // 盖本次引用的内容。
 57 func (s *Scanner) Bytes() []byte
 58 
 59 // Text 将最后一次扫描出的“匹配部分”作为字符串返回(返回副本)。
 60 func (s *Scanner) Text() string
 61 
 62 // Err 返回扫描过程中遇到的非 EOF 错误,供用户调用,以便获取错误信息。
 63 func (s *Scanner) Err() error
 64 
 65 // ScanBytes 是一个“匹配函数”用来找出 data 中的单个字节并返回。
 66 func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error)
 67 
 68 // ScanRunes 是一个“匹配函数”,用来找出 data 中单个 UTF8 字符的编码。如果 UTF8 编
 69 // 码错误,则 token 会返回 "\xef\xbf\xbd"(即:U+FFFD),但只消耗 data 中的一个字节。
 70 // 这使得调用者无法区分“真正的U+FFFD字符”和“解码错误的返回值”。
 71 func ScanRunes(data []byte, atEOF bool) (advance int, token []byte, err error)
 72 
 73 // ScanLines 是一个“匹配函数”,用来找出 data 中的单行数据并返回(包括空行)。
 74 // 行尾标记可以是 \n 或 \r\n(返回值不包含行尾标记)
 75 func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error)
 76 
 77 // ScanWords 是一个“匹配函数”,用来找出 data 中以空白字符分隔的单词。
 78 // 空白字符由 unicode.IsSpace 定义。
 79 func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error)
 80 
 81 ------------------------------
 82 
 83 // 示例:扫描
 84 func main() {
 85     // 逗号分隔的字符串,最后一项为空
 86     const input = "1,2,3,4,"
 87     scanner := bufio.NewScanner(strings.NewReader(input))
 88     // 定义匹配函数(查找逗号分隔的字符串)
 89     onComma := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
 90         for i := 0; i < len(data); i++ {
 91             if data[i] == ',' {
 92                 return i + 1, data[:i], nil
 93             }
 94         }
 95         if atEOF {
 96             // 告诉 Scanner 扫描结束。
 97             return 0, data, bufio.ErrFinalToken
 98         } else {
 99             // 告诉 Scanner 没找到匹配项,让 Scan 填充缓存后再次扫描。
100             return 0, nil, nil
101         }
102     }
103     // 指定匹配函数
104     scanner.Split(onComma)
105     // 开始扫描
106     for scanner.Scan() {
107         fmt.Printf("%q ", scanner.Text())
108     }
109     // 检查是否因为遇到错误而结束
110     if err := scanner.Err(); err != nil {
111         fmt.Fprintln(os.Stderr, "reading input:", err)
112     }
113 }
114 --------------------------------------------------------------------------
115 // 示例:带检查扫描
116 func main() {
117     const input = "1234 5678 1234567901234567890 90"
118     scanner := bufio.NewScanner(strings.NewReader(input))
119     // 自定义匹配函数
120     split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
121         // 获取一个单词
122         // ScanBytes、ScanWords、ScanLines这些函数主用于筛选出相应的byte、word、line
123         // 然后用于自定义匹配函数中进行匹配
124         advance, token, err = bufio.ScanWords(data, atEOF)
125         // 判断其能否转换为整数,如果不能则返回错误
126         if err == nil && token != nil {
127             _, err = strconv.ParseInt(string(token), 10, 32)
128         }
129         // 这里包含了 return 0, nil, nil 的情况
130         return
131     }
132     // 设置匹配函数
133     scanner.Split(split)
134     // 开始扫描
135     for scanner.Scan() {
136         fmt.Printf("%s\n", scanner.Text())
137     }
138     // 扫描至1234567901234567890处,便会报错抛出异常,停止scan
139     if err := scanner.Err(); err != nil {
140         fmt.Printf("Invalid input: %s", err)
141     }
142 }

 

posted @ 2019-12-10 11:51  尘归风  阅读(527)  评论(0)    收藏  举报