Go的学习路程:文件(二)|Go 主题月

268 阅读2分钟

上一篇文章学习了如何打开、创建以及关闭一个文件。通过这篇文章学习一下如何读取文件。

按 byte 读取

Go os.File 提供 Read 方法从 f 中读取最多 len(b) 字节数据并写入 b。它返回读取的字节数和可能遇到的任何错误。文件终止标志是读取0个字节且返回值err为io.EOF。

  • func (f File) Read(b []byte) (n int, err error)
package main

import "fmt"
import "os"

func main () {
    f, err := os.Open("D:\\tmp\\hello.txt")

    if err != nil {
        fmt.Printf("打开文件错误,%v", err)
        return
    }

    buf := make([]byte, 8)
    n, err := f.Read(buf)
    if err != nil {
        fmt.Printf("打开文件错误,%v", err)
        return
    }
    fmt.Printf("读取 %d byte 内容", n)
    f.Close()
}

如上代码定义了一个长度只有 8 的 byte 数组。Read 方法每次只读最多 len(buf) 个 byte 数据。如果读取长度等于 0 时,说明已经读取到文件结尾了。这个时候我们就要停止继续读取文件内容。

package main

import "fmt"
import "os"

func main () {
    f, err := os.Open("D:\\tmp\\hello.txt")

    if err != nil {
        fmt.Printf("打开文件错误,%v", err)
        return
    }

    buf := make([]byte, 8)
    for n, _ := f.Read(buf); n != 0; n, _ = f.Read(buf) {
        fmt.Printf("读取 %d byte 内容,内容:%q\n", n, buf[:n]) // 1
    }
    f.Close()
}

代码输出如下。代码 1 处打印的buf的时候使用了切片。这是因为当读取内容不足以填满 buf 的时候,buf 会残留上一次读取的内容。

gorunfile2.png

按行读取

在有些时候一行一行读取文件内容更适合我们对文件的理解与处理。在 Go 中提供 bufio 包来按行读取文件内容。 bufio 中包括 Reader、Scanner 以及 Writer,其中 Reader 和 Scanner 都支持按行读取文件。

Reader 读取

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

import "fmt"
import "os"
import "bufio"

func main () {
    f, err := os.Open("D:\\tmp\\hello.txt")

    if err != nil {
            fmt.Printf("打开文件错误,%v", err)
            return
    }

    reader := bufio.NewReader(f)
    for line, _, err := reader.ReadLine(); len(line) != 0 && err == nil; line, _, err = reader.ReadLine() {
        fmt.Printf("line is complete: %v\n", isPrefix) // 如果 isPrefix 为 false 表示本次完整的读取一行内容
        fmt.Printf("line content: %s", line) // line content: hello go language.
    }

    f.Close()
}

ReadLine 读取文件的一行,默认是以 \r\n 或者 \n 分割,并且不包括分割符,如果行太长超过了内部 buffer 的大小,第二个返回值 isPrefix 就会被设置,直到 isPrefix 为 false 为止,表示一行读取完成。

Scanner 读取

Scanner 类似于 Reader,但是 scanner 有更强的便捷性,scanner 的主要目的就是利用各种分隔符来读取行。

  • func (s *Scanner) Scan() bool
  • func (s *Scanner) Text() string
package main

import "fmt"
import "os"
import "bufio"

func main () {
    f, err := os.Open("D:\\tmp\\hello.txt")

    if err != nil {
        fmt.Printf("打开文件错误,%v", err)
        return
    }


    scanner := bufio.NewScanner(f)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }

    f.Close()
}