www.zhblog.net

bufio 包


io.Readerio.Writer定义了基于字节的读写行为,然而许多情况下,你会想要基于字符串、行来进行读写,这可以透过bufio包的bufio.Readerbufio.Writer等达到。

bufio.Reader可以透过NewReaderNewReaderSize指定io.Reader来创建实例,前者指定默认缓冲区大小 4096 字节调用后者,bufio.Reader在读取来源时会从底层的io.Reader将数据读入,在创建bufio.Reader实例之后,可以使用的方法有:

func (b *Reader) Buffered() int
func (b *Reader) Discard(n int) (discarded int, err error)
func (b *Reader) Peek(n int) ([]byte, error)
func (b *Reader) Read(p []byte) (n int, err error)
func (b *Reader) ReadByte() (byte, error)
func (b *Reader) ReadBytes(delim byte) ([]byte, error)
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
func (b *Reader) ReadRune() (r rune, size int, err error)
func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
func (b *Reader) ReadString(delim byte) (string, error)
func (b *Reader) Reset(r io.Reader)
func (b *Reader) Size() int
func (b *Reader) UnreadByte() error
func (b *Reader) UnreadRune() error
func (b *Reader) WriteTo(w io.Writer) (n int64, err error)

因此对于逐行读取一个 UTF-8 文本文件来说,可以简单地编写如下:

package main

import (
    "bufio"
    "os"
    "fmt"
    "io"
)

func printFile(f *os.File) (err error){
    var (
        r = bufio.NewReader(f)
        line string
    )
    for err == nil {
        line, err = r.ReadString('\n')
        fmt.Println(line)
    }
    if err == io.EOF {
        err = nil
    }
    return
}

func main() {
    var filename string
    fmt.Print("文件名称:")
    fmt.Scanf("%s", &filename);

    f, err := os.Open(filename)
    if err != nil {
        panic(err)
    }
    defer f.Close()

    printFile(f)
}

如果实际上是要读取之后写到另一个输出,使用WriteTo方法更为方便:

package main

import (
    "bufio"
    "os"
    "fmt"
)

func main() {
    var filename string
    fmt.Print("文件名称:")
    fmt.Scanf("%s", &filename);

    f, err := os.Open(filename)
    if err != nil {
        panic(err)
    }
    defer f.Close()

    bufio.NewReader(f).WriteTo(os.Stdout)
}

Go 在io.WriteTo接口定义了WriteTo行为:

type WriterTo interface {
    WriteTo(w Writer) (n int64, err error)
}

实际上bufio.Reader实现了io中一些接口,io.WriteTo只是其中之一;类似地,如果要创建bufio.Writer实例,可以透过NewWriterNewWriterSize函数,创建之后可用的方法如下:

func (b *Writer) Available() int
func (b *Writer) Buffered() int
func (b *Writer) Flush() error
func (b *Writer) ReadFrom(r io.Reader) (n int64, err error)
func (b *Writer) Reset(w io.Writer)
func (b *Writer) Size() int
func (b *Writer) Write(p []byte) (nn int, err error)
func (b *Writer) WriteByte(c byte) error
func (b *Writer) WriteRune(r rune) (size int, err error)
func (b *Writer) WriteString(s string) (int, error)

bufio.Writer实现了io中一些接口,像是io.ReadFrom,因此,也可以如下在标准输出中,显示读入的的文件内容:

package main

import (
    "bufio"
    "os"
    "fmt"
)

func main() {
    var filename string
    fmt.Print("文件名称:")
    fmt.Scanf("%s", &filename);

    f, err := os.Open(filename)
    if err != nil {
        panic(err)
    }
    defer f.Close()

    w := bufio.NewWriter(os.Stdout)
    w.ReadFrom(f)
    w.Flush()
}

NewWriter默认的缓冲区为 4096 字节,由于这边使用标准输出,在缓冲区未满前,数据不会写出,可以使用Flush来出清缓冲区中的数据。

事实上,对于需要逐行读取的需求,使用bufio.Scanner会比较方便,可以使用NewScanner来创建实例,创建之后有以下的方法可以使用:

func (s *Scanner) Buffer(buf []byte, max int)
func (s *Scanner) Bytes() []byte
func (s *Scanner) Err() error
func (s *Scanner) Scan() bool
func (s *Scanner) Split(split SplitFunc)
func (s *Scanner) Text() string

来看看读取文本文件的例子:

package main

import (
    "bufio"
    "os"
    "fmt"
)

func main() {
    var filename string
    fmt.Print("文件名称:")
    fmt.Scanf("%s", &filename);

    f, err := os.Open(filename)
    if err != nil {
        panic(err)
    }
    defer f.Close()

    scanner := bufio.NewScanner(f)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        panic(err)
    }
}




展开阅读全文

评论

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 心情