// bufio 包實現了帶緩存的 I/O 操作
// 它封裝一個 io.Reader 或 io.Writer 對象
// 使其具有緩存和一些文本讀寫功能
------------------------------------------------------------
// bufio.go
------------------------------------------------------------
// Reader 實現了帶緩存的 io.Reader 對象
type Reader struct {
// 私有字段
}
// NewReaderSize 將 rd 封裝成一個擁有 size 大小緩存的 bufio.Reader 對象
// 如果 rd 的基類型就是 bufio.Reader 類型,而且擁有足夠的緩存
// 則直接將 rd 轉換為基類型并返回
func NewReaderSize(rd io.Reader, size int) *Reader
// NewReader 相當于 NewReaderSize(rd, 4096)
func NewReader(rd io.Reader) *Reader
------------------------------------------------------------
// Peek 返回緩存的一個切片,該切片引用緩存中前 n 字節數據
// 該操作不會將數據讀出,只是引用
// 引用的數據在下一次讀取操作之前是有效的
// 如果引用的數據長度小于 n,則返回一個錯誤信息
// 如果 n 大于緩存的總大小,則返回 ErrBufferFull
// 通過 Peek 的返回值,可以修改緩存中的數據
// 但是不能修改底層 io.Reader 中的數據
func (b *Reader) Peek(n int) ([]byte, error)
func main() {
s := strings.NewReader("ABCDEFG")
br := bufio.NewReader(s)
b, _ := br.Peek(5)
fmt.Printf("%s\n", b)
// ABCDE
b[0] = 'a'
b, _ = br.Peek(5)
fmt.Printf("%s\n", b)
// aBCDE
}
------------------------------------------------------------
// Read 從 b 中讀出數據到 p 中,返回讀出的字節數
// 如果 p 的大小 >= 緩存的總大小,而且緩存不為空
// 則只能讀出緩存中的數據,不會從底層 io.Reader 中提取數據
// 如果 p 的大小 >= 緩存的總大小,而且緩存為空
// 則直接從底層 io.Reader 向 p 中讀出數據,不經過緩存
// 只有當 b 中無可讀數據時,才返回 (0, io.EOF)
func (b *Reader) Read(p []byte) (n int, err error)
func main() {
s := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
br := bufio.NewReader(s)
b := make([]byte, 20)
n, err := br.Read(b)
fmt.Printf("%-20s %-2v %v\n", b[:n], n, err)
// ABCDEFGHIJKLMNOPQRST 20 <nil>
n, err = br.Read(b)
fmt.Printf("%-20s %-2v %v\n", b[:n], n, err)
// UVWXYZ1234567890 16 <nil>
n, err = br.Read(b)
fmt.Printf("%-20s %-2v %v\n", b[:n], n, err)
// 0 EOF
}
------------------------------------------------------------
// ReadByte 從 b 中讀出一個字節并返回
// 如果 b 中無可讀數據,則返回一個錯誤
func (b *Reader) ReadByte() (c byte, err error)
// UnreadByte 撤消最后一次讀出的字節
// 只有最后讀出的字節可以被撤消
// 無論任何操作,只要有內容被讀出,就可以用 UnreadByte 撤消一個字節
func (b *Reader) UnreadByte() error
func main() {
s := strings.NewReader("ABCDEFG")
br := bufio.NewReader(s)
c, _ := br.ReadByte()
fmt.Printf("%c\n", c)
// A
c, _ = br.ReadByte()
fmt.Printf("%c\n", c)
// B
br.UnreadByte()
c, _ = br.ReadByte()
fmt.Printf("%c\n", c)
// B
}
------------------------------------------------------------
// ReadRune 從 b 中讀出一個 UTF8 編碼的字符并返回
// 同時返回該字符的 UTF8 編碼長度
// 如果 UTF8 序列無法解碼出一個正確的 Unicode 字符
// 則只讀出 b 中的一個字節,并返回 U+FFFD 字符,size 返回 1
func (b *Reader) ReadRune() (r rune, size int, err error)
// UnreadRune 撤消最后一次讀出的 Unicode 字符
// 如果最后一次執行的不是 ReadRune 操作,則返回一個錯誤
// 因此,UnreadRune 比 UnreadByte 更嚴格
func (b *Reader) UnreadRune() error
func main() {
s := strings.NewReader("你好,世界!")
br := bufio.NewReader(s)
c, size, _ := br.ReadRune()
fmt.Printf("%c %v\n", c, size)
// 你 3
c, size, _ = br.ReadRune()
fmt.Printf("%c %v\n", c, size)
// 好 3
br.UnreadRune()
c, size, _ = br.ReadRune()
fmt.Printf("%c %v\n", c, size)
// 好 3
}
------------------------------------------------------------
// Buffered 返回緩存中數據的長度
func (b *Reader) Buffered() int
func main() {
s := strings.NewReader("你好,世界!")
br := bufio.NewReader(s)
fmt.Println(br.Buffered())
// 0
br.Peek(1)
fmt.Println(br.Buffered())
// 18
}
------------------------------------------------------------
// ReadSlice 在 b 中查找 delim 并返回 delim 及其之前的所有數據的切片
// 該操作會讀出數據,返回的切片是已讀出數據的引用
// 切片中的數據在下一次讀取操作之前是有效的
//
// 如果 ReadSlice 在找到 delim 之前遇到錯誤
// 則讀出緩存中的所有數據并返回,同時返回遇到的錯誤(通常是 io.EOF)
// 如果在整個緩存中都找不到 delim,則 err 返回 ErrBufferFull
// 如果 ReadSlice 能找到 delim,則 err 始終返回 nil
//
// 因為返回的切片中的數據有可能被下一次讀寫操作修改
// 因此大多數操作應該使用 ReadBytes 或 ReadString,它們返回的不是數據引用
func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
func main() {
s := strings.NewReader("ABC DEF GHI JKL")
br := bufio.NewReader(s)
w, _ := br.ReadSlice(' ')
fmt.Printf("%q\n", w)
// "ABC "
w, _ = br.ReadSlice(' ')
fmt.Printf("%q\n", w)
// "DEF "
w, _ = br.ReadSlice(' ')
fmt.Printf("%q\n", w)
// "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)