上一篇文章学习了如何打开、创建以及关闭一个文件。通过这篇文章学习一下如何读取文件。
按 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 会残留上一次读取的内容。
按行读取
在有些时候一行一行读取文件内容更适合我们对文件的理解与处理。在 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()
}