Go1.11标准库bufio包及Demo

bufio包实现了有缓冲的I/O。它包装一个io.Reader或io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本I/O的帮助函数的对象。

Constants

const (
  // 用于缓冲一个token,实际需要的最大token尺寸可能小一些,例如缓冲中需要保存一整行内容
  MaxScanTokenSize = 64 * 1024
  startBufSize = 4096 // buffe初始分配大小
)

Struct

ReadWriter

bufio . ReadWriter [struct]

ReadWriter类型保管了指向Reader和Writer类型的指针,(因此)实现了 io.ReadWriter 接口。

type ReadWriter struct {
	*Reader
	*Writer
}

Reader

Reader实现了给一个 io.Reader 接口对象附加缓冲。

type Reader struct {
	buf          []byte
	rd           io.Reader // 用户提供的读取器
	r, w         int       // buf 的读写位置
	err          error
	lastByte     int
	lastRuneSize int
}

Scanner

bufio . Scanner [struct]

Scanner类型提供了方便的读取数据的接口,如从换行符分隔的文本里读取每一行。 成功调用的 Scan 方法会逐步提供文件的 token ,跳过 token 之间的字节。 token 由SplitFunc类型的分割函数指定;默认的分割函数会将输入分割为多个行,并去掉行尾的换行标志。本包预定义的分割函数可以将文件分割为行、字节、 unicode 码值、空白分隔的word。调用者可以定制自己的分割函数。 扫描会在抵达输入流结尾、遇到的第一个I/O错误、 token 过大不能保存进缓冲时,不可恢复的停止。当扫描停止后,当前读取位置可能会远在最后一个获得的 token 后面。需要更多对错误管理的控制或 token 很大,或必须从reader连续扫描的程序,应使用 bufio.Reader 代替。

type Scanner struct {
	r            io.Reader // 用户提供的读取器
	split        SplitFunc // 用于拆分标记的函数。
	maxTokenSize int       // 令牌的最大大小;由测试修改。
	token        []byte    // split返回的最后一个令牌。
	buf          []byte    // 缓冲区用作要拆分的参数。
	start        int       // buf中的第一个未处理字节。
	end          int       // BUF中的数据最后一个字节。
	err          error     // error.
	empties      int       // 连续空令牌计数
	scanCalled   bool      // 已调用Sacan;缓冲区正在使用中.
	done         bool      // Scan 结束.
}

Function:

  • Bytes
  • Err
  • Scan
  • Split
  • Text
  • Buffer
func (s *Scanner) Bytes() []byte

Bytes方法返回最近一次 Scan 调用生成的 token 。底层数组指向的数据可能会被下一次 Scan 的调用重写

func (s *Scanner) Err() error

Err返回 Scanner 遇到的第一个非EOF的错误。

func (s *Scanner) Scan() bool

Scan方法获取当前位置的 token (该 token 可以通过 Bytes 或 Text 方法获得),并让 Scanner 的扫描位置移动到下一个 token 。当扫描因为抵达输入流结尾或者遇到错误而停止时,本方法会返回false。在Scan方法返回false后, Err 方法将返回扫描时遇到的任何错误;除非是 io .EOF,此时 Err 会返回nil。

func (s *Scanner) Split(split SplitFunc)

Split设置该 Scanner 的分割函数。本方法必须在 Scan 之前调用。

func (s *Scanner) Text() string

Bytes 方法返回最近一次 Scan 调用生成的 token ,会申请创建一个字符串保存 token 并返回该字符串

Writer

bufio . Writer [struct]

Writer实现了为 io.Writer 接口对象提供缓冲。如果在向一个Writer类型值写入时遇到了错误,该对象将不再接受任何数据,且所有写操作都会返回该错误。在说有数据都写入后,调用者有义务调用 Flush 方法以保证所有的数据都交给了下层的 io.Writer 。

type Writer struct {
	err error
	buf []byte
	n   int
	wr  io.Writer
}

Function:

  • Available
  • Buffered
  • Flush
  • ReadFrom
  • Reset
  • Write
  • WriteByte
  • WriteRune
  • WriteString
func (b *Writer) Available() int

Available返回缓冲中还有多少字节未使用。

func (b *Writer) Buffered() int

Buffered返回缓冲中已使用的字节数。

func (b *Writer) Flush() error

Flush方法将缓冲中的数据写入下层的 io.Writer 接口。

func (b *Writer) ReadFrom(r io.Reader) (n int64, err error)

ReadFrom实现了 io.ReaderFrom 接口。

func (b *Writer) Reset(w io.Writer)

Reset丢弃缓冲中的数据,清除任何错误,将b重设为将其输出写入w。

func (b *Writer) Write(p []byte) (nn int, err error)

Write将p的内容写入缓冲。返回写入的字节数。如果返回值nn < len§,还会返回一个错误说明原因

func (b *Writer) WriteByte(c byte) error

WriteByte写入单个字节。

func (b *Writer) WriteRune(r rune) (size int, err error)

WriteRune写入一个 unicode 码值(的utf-8编码),返回写入的字节数和可能的错误。

func (b *Writer) WriteString(s string) (int, error)

WriteString写入一个字符串。返回写入的字节数。如果返回值nn < len(s),还会返回一个错误说明原因。

Type

bufio . SplitFunc [type]

SplitFunc类型代表用于对输出作词法分析的分割函数。 参数data是尚未处理的数据的一个开始部分的切片,参数atEOF表示是否Reader接口不能提供更多的数据。返回值是解析位置前进的字节数,将要返回给调用者的 token 切片,以及可能遇到的错误。如果数据不足以(保证)生成一个完整的 token ,例如需要一整行数据但data里没有换行符,SplitFunc可以返回(0,nil,nil)来告诉Scanner读取更多的数据写入切片然后用从同一位置起始、长度更长的切片再试一次(调用SplitFunc类型函数)。 如果返回值err非nil,扫描将终止并将该错误返回给Scanner的调用者。 除非atEOF为真,永远不会使用空切片data调用SplitFunc类型函数。然而,如果atEOF为真,data却可能是非空的、且包含着未处理的文本。

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

Function

  • NewReadWriter
func NewReadWriter(r *Reader, w *Writer) *ReadWriter

NewReadWriter申请创建一个新的、将读写操作分派给r和w的ReadWriter。

  • NewReader
func NewReader(rd io.Reader) *Reader

NewReader创建一个具有默认大小缓冲、从r读取的*Reader。

  • NewReaderSize
func NewReaderSize(rd io.Reader, size int) *Reader

NewReaderSize创建一个具有最少有size尺寸的缓冲、从r读取的Reader。如果参数r已经是一个具有足够大缓冲的Reader类型值,会返回r。

  • NewScanner
func NewScanner(r io.Reader) *Scanner

NewScanner创建并返回一个从r读取数据的Scanner,默认的分割函数是ScanLines

  • NewWriter
func NewWriter(w io.Writer) *Writer

NewWriter创建一个具有默认大小缓冲、写入w的*Writer

  • NewWriterSize
func NewWriterSize(w io.Writer, size int) *Writer

NewWriterSize创建一个具有最少有size尺寸的缓冲、写入w的Writer。如果参数w已经是一个具有足够大缓冲的Writer类型值,会返回w。

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

ScanBytes是用于Scanner类型的分割函数(符合SplitFunc),本函数会将每个字节作为一个 token 返回。

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

scanlines是一个拆分函数,它返回文本,去掉任何行尾标记。返回的行可以空。行尾标记是后面的一个可选回车通过一个强制换行。在正则表达式表示法中,它是`\r?\n,输入的最后一个非空行将被返回,即使它没有换行符。

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

ScanRunes是用于Scanner类型的分割函数(符合SplitFunc),本函数会将每个utf-8编码的 unicode 码值作为一个 token 返回。本函数返回的rune序列和range一个字符串的输出rune序列相同。错误的utf-8编码会翻译为U+FFFD="\xef\xbf\xbd",但只会消耗一个字节。调用者无法区分正确编码的rune和错误编码的rune。

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

scanwords是一个split函数,用于返回以空格分隔的文本字,删除周围的空格。它永远不会返回空字符串。空间的定义由unicode.isspace。

  • Reader.Buffered
func (b *Reader) Buffered() int

Buffered返回缓冲中现有的可读取的字节数。

  • Reader.Peek
func (b *Reader) Peek(n int) ([]byte, error)

Peek返回输入流的下n个字节,而不会移动读取位置。返回的[]byte只在下一次调用读取操作前合法。如果Peek返回的切片长度比n小,它也会返会一个错误说明原因。如果n比缓冲尺寸还大,返回的错误将是ErrBufferFull。

  • Reader.Read
func (b *Reader) Read(p []byte) (n int, err error)

Read读取数据写入p。本方法返回写入p的字节数。本方法一次调用最多会调用下层 Reader 接口一次Read方法,因此返回值n可能小于len§。读取到达结尾时,返回值n将为0而err将为 io .EOF。

  • Reader.ReadByte
func (b *Reader) ReadByte() (c byte, err error)

ReadByte读取并返回一个字节。如果没有可用的数据,会返回错误。

  • Reader.ReadBytes
func (b *Reader) ReadBytes(delim byte) (line []byte, err error)

ReadBytes读取直到第一次遇到delim字节,返回一个包含已读取的数据和delim字节的切片。如果ReadBytes方法在读取到delim之前遇到了错误,它会返回在错误之前读取的数据以及该错误(一般是 io .EOF)。当且仅当ReadBytes方法返回的切片不以delim结尾时,会返回一个非nil的错误。

  • Reader.ReadLine
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)

ReadLine是一个低水平的行数据读取原语。大多数调用者应使用 ReadBytes (’\n’)或 ReadString (’\n’)代替,或者使用Scanner。 ReadLine尝试返回一行数据,不包括行尾标志的字节。如果行太长超过了缓冲,返回值isPrefix会被设为true,并返回行的前面一部分。该行剩下的部分将在之后的调用中返回。返回值isPrefix会在返回该行最后一个片段时才设为false。返回切片是缓冲的子切片,只在下一次读取操作之前有效。ReadLine要么返回一个非nil的line,要么返回一个非nil的err,两个返回值至少一个非nil。 返回的文本不包含行尾的标志字节("\r\n"或"\n")。如果输入流结束时没有行尾标志字节,方法不会出错,也不会指出这一情况。在调用ReadLine之后调用 UnreadByte 会总是吐出最后一个读取的字节(很可能是该行的行尾标志字节),即使该字节不是ReadLine返回值的一部分。

  • Reader.ReadRune
func (b *Reader) ReadRune() (r rune, size int, err error)

ReadRune读取一个utf-8编码的 unicode 码值,返回该码值、其编码长度和可能的错误。如果utf-8编码非法,读取位置只移动1字节,返回U+FFFD,返回值size为1而err为nil。如果没有可用的数据,会返回错误。

  • Reader.ReadSlice
func (b *Reader) ReadSlice(delim byte) (line []byte, err error)

ReadSlice读取直到第一次遇到delim字节,返回缓冲里的包含已读取的数据和delim字节的切片。该返回值只在下一次读取操作之前合法。如果ReadSlice放在在读取到delim之前遇到了错误,它会返回在错误之前读取的数据在缓冲中的切片以及该错误(一般是 io .EOF)。如果在读取到delim之前缓冲就被写满了,ReadSlice失败并返回ErrBufferFull。因为ReadSlice的返回值会被下一次I/O操作重写,调用者应尽量使用 ReadBytes 或 ReadString 替代本法功法。当且仅当 ReadBytes 方法返回的切片不以delim结尾时,会返回一个非nil的错误。

  • Reader.ReadString
func (b *Reader) ReadString(delim byte) (line string, err error)

ReadString读取直到第一次遇到delim字节,返回一个包含已读取的数据和delim字节的字符串。如果ReadString方法在读取到delim之前遇到了错误,它会返回在错误之前读取的数据以及该错误(一般是 io .EOF)。当且仅当ReadString方法返回的切片不以delim结尾时,会返回一个非nil的错误。

  • Reader.Reset
func (b *Reader) Reset(r io.Reader)

Reset丢弃缓冲中的数据,清除任何错误,将b重设为其下层从r读取数据。

  • Reader.UnreadByte
func (b *Reader) UnreadByte() error

UnreadByte吐出最近一次读取操作读取的最后一个字节。(只能吐出最后一个,多次调用会出问题)

  • Reader.UnreadRune
func (b *Reader) UnreadRune() error

UnreadRune吐出最近一次 ReadRune 调用读取的 unicode 码值。如果最近一次读取不是调用的 ReadRune ,会返回错误。(从这点看,UnreadRune比 UnreadByte 严格很多

  • Reader.WriteTo
func (b *Reader) WriteTo(w io.Writer) (n int64, err error)

WriteTo方法实现了 io.WriterTo 接口。

Demo

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	scanWords()
	scanCustom()
	scanLines()
}
func scanWords() {
	// 输入源
	const input = "Now is the winter of our discontent,\nMade glorious summer by this sun of York.\n"
	scanner := bufio.NewScanner(strings.NewReader(input))
	// Set the split function for the scanning operation.
	scanner.Split(bufio.ScanWords)
	// 统计单词数量.
	count := 0
	//遍历单词
	for scanner.Scan() {
		fmt.Printf("%s\n", scanner.Text())
		count++
	}
	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading input:", err)
	}

	fmt.Printf("%d\n", count)
}

func scanCustom() {
	const input = "1234 5678 123456790 1234567890"
	scanner := bufio.NewScanner(strings.NewReader(input))
	// 自建切割函数
	split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		advance, token, err = bufio.ScanWords(data, atEOF)
		if err == nil && token != nil {
			_, err = strconv.ParseInt(string(token), 10, 32)
		}
		return
	}
	// 设置切割函数.
	scanner.Split(split)
	// 遍历
	for scanner.Scan() {
		fmt.Printf("%s\n", scanner.Text())
	}
	if err := scanner.Err(); err != nil {
		fmt.Printf("Invalid input: %s", err)
	}
}
func scanLines() {
	//从终端输入
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		fmt.Println(scanner.Text()) // Println will add back the final '\n'
	}
	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading standard input:", err)
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值