一次性读取整个文件
一次性读取整个文件是一种比较简单的文件读取方式。我们可以通过ioutil包中的ReadFile来读取整个文件。
我们在Golang工作目录下创建一个工程目录filehandling
。然后在该工程目录下再创建一个文本文件test.txt
。在该文件中输入如下文本:
Hello World. Welcome to file handling in Go.
然后创建Golang程序文件filehandling.go
,并输入如下代码:
package main
import (
"fmt"
"io/ioutil"
)
func main() {
data, err := ioutil.ReadFile("test.txt")
if err != nil {
fmt.Println("File reading error", err)
return
}
fmt.Println("Contents of file:", string(data))
}
此时的文件目录为:
src
filehandling
filehandling.go
test.txt
前面程序中我们通过ioutil.ReadFile("test.txt")
来读取了整个文件的内容,该函数返回的数据格式为字节切片。因此这里的data
数据类型为字节切片,我们通过string(data)
将字节切片转成了字符串然后再打印。该程序执行结果如下:
Contents of file: Hello World. Welcome to file handling in Go.
注意,这里我们使用的是相对目录test.txt
,因此需要先切换到test.txt
所在的目录,然后再执行程序,可通过如下两种方式来执行。
$ cd /home/goworkspace/src/filehandling/
$ go install filehandling
$ workspacepath/bin/filehandling
$ cd /home/goworkspace/src/filehandling/
$ go run filehandling.go
如果不切换到test.txt
文件所在目录,那么执行会报错:
File reading error open test.txt: The system cannot find the file specified.
之所以会报错是因为Golang是一种编译型语言,Golang程序在执行前会先编译成二进制程序,而我们在程序中已经写死了文件目录test.txt
,即二进制程序在什么目录下执行,就在哪个目录下寻找test.txt
,因此如果我们不在filehandling
目录下执行,则会找不到test.txt
文件,就会报错。我们有三种方式能解决这个问题:
这里就不细讲了,感兴趣的同学可以google下。
按字节读取
前面我们看了怎么读取整个文件,但是对于过大的文件,一次性读取到内存则不太现实。更加合理的方式是一小块一小块的读取。我们可以借助buffo包来实现。
下面我们按每3个字节一块来读取前面的test.txt
文件。
package main
import (
"bufio"
"flag"
"fmt"
"log"
"os"
)
func main() {
fptr := flag.String("fpath", "test.txt", "file path to read from")
flag.Parse()
f, err := os.Open(*fptr)
if err != nil {
log.Fatal(err)
}
defer func() {
if err = f.Close(); err != nil {
log.Fatal(err)
}
}()
r := bufio.NewReader(f)
b := make([]byte, 3)
for {
_, err := r.Read(b)
if err != nil {
fmt.Println("Error reading file:", err)
break
}
fmt.Println(string(b))
}
}
这里我们从命令行中解析出了文件目录。我们defer
了一个函数用来在文件读取结束后关闭文件。通过make([]byte, 3)
创建了长度为3的字节切片,然后通过r.Read(b)
不断的讲文件内容读入到b
中。Read
方法读取最多len(b)
个字节,并返回真实读取到的字节数,读取到文件结尾后会返回一个EOF
错误。
可通过如下方式执行该程序:
$ go install filehandling
$ wrkspacepath/bin/filehandling -fpath=/path-of-file/test.txt
执行结果如下:
Hel
lo
Wor
ld.
We
lco
me
to
fil
e h
and
lin
g i
n G
o.G
Error reading file: EOF
按行读取
下面我们看下如何按行读取文件。仍然是借助bufio实现。现在将test.txt
中的文本换成如下内容。
Hello World. Welcome to file handling in Go.
This is the second line of the file.
We have reached the end of the file.
按行读取的流程如下:
package main
import (
"bufio"
"flag"
"fmt"
"log"
"os"
)
func main() {
fptr := flag.String("fpath", "test.txt", "file path to read from")
flag.Parse()
f, err := os.Open(*fptr)
if err != nil {
log.Fatal(err)
}
defer func() {
if err = f.Close(); err != nil {
log.Fatal(err)
}
}()
s := bufio.NewScanner(f)
for s.Scan() {
fmt.Println(s.Text())
}
err = s.Err()
if err != nil {
log.Fatal(err)
}
}
这里通过os.Open(*fptr)
打开了文件,然后通过bufio.NewScanner(f)
创建了一个scanner
,然后通过s.Scan()
和s.Text()
按行读取了文件内容。s.Err()
用来判断读取文件过程中是否发生了错误。该程序执行结果如下:
Hello World. Welcome to file handling in Go.
This is the second line of the file.
We have reached the end of the file.