在Go语言中,读取文件主要有以下几种包可用:
- os:顾名思义,os是操作系统系统相关的包,封装了文件和目录相关的操作;
- ioutil:io包的工具包,通过封装os的文件操作,提供上层文件读写的方法。随着版本的迭代,大部分方法即将遗弃;
- bufio:带有缓冲区的io包;
1 os包的使用
操作文件的相关方法都在$GOROOT/src/os/file.go文件中,主要函数主要如下:
- OpenFile(): 较底层的一个打开文件的方式,可以灵活配置你打开的文件,比如Create()方法就是调该方法实现文件的新建;
- Open(): 以只读的方式打开一个文件;
- ReadFile(): 调Open()方法打开文件,循环读取文件内容,返回值是字节数组;
- WriteFile(): 向文件写入内容,如果文件不存在,则创建新文件;
- Create(): 新建文件;
- Rename(): 文件重命名。
1.1 OpenFile()方法
OpenFile()的方法源码如下:
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
testlog.Open(name)
// 调用系统调用创建一个File对象
f, err := openFileNolog(name, flag, perm)
if err != nil {
return nil, err
}
f.appendMode = flag&O_APPEND != 0
return f, nil
}
其中,
- name:是文件的路径名称
- flag:是以什么形式打开文件,常用的O_RDONLY表示只读,O_WRONLY表示只写,O_RDWR表示读写等
- perm:是文件的格式和权限配置,比如,0777配置当前用户、用户组和其他用户都可以执行文件
使用OpenFile()方法打开一个不存在的文件,perm配置为0777,flag配置为os.O_WRONLY|os.O_CREATE
package main
import (
"os"
)
func main() {
f, err := os.OpenFile("test.txt", os.O_WRONLY|os.O_CREATE, 0777)
if err != nil {
panic(err)
}
defer f.Close()
if _, err = f.WriteString("hello world"); err != nil {
panic(err)
}
}
可以看到创建的文件有执行权限
文件内容为:
hello world
2.2 Open()方法
Open()方法底层是以可读的参数调用OpenFile()实现的:
func Open(name string) (*File, error) {
return OpenFile(name, O_RDONLY, 0)
}
因为是只读的,所以可以使用Open()方法打开一个文件,来读取文件内容
package main
import (
"fmt"
"io"
"os"
)
func main() {
f, err := os.Open("test.txt")
if err != nil {
panic(err)
}
defer f.Close()
Content := []byte{}
for {
data := make([]byte, 10)
n, err := f.Read(data)
if err != nil {
if err == io.EOF {
break
}
panic(err)
}
Content = append(Content, data[:n]...)
fmt.Println(string(data[:n]))
}
}
2.3 ReadFile()方法
在使用Open()方法尝试去读取文件内容时,是需要自己来通过Reade()接口循环从文件中读取字节的。如果只是想简单地读取文件的所有内容,可以使用封装后的ReadFile()方法可以更简单的实现
package main
import (
"fmt"
"os"
)
func main() {
Content, err := os.ReadFile("test.txt")
if err != nil {
panic(err)
}
fmt.Println(string(Content))
}
打开ReadFile()方法的源码,能看到底层调用Open()方法,os包帮我们完成了循环读取文件内容的代码(比上面例子的实现效率更高):
func ReadFile(name string) ([]byte, error) {
f, err := Open(name)
if err != nil {
return nil, err
}
defer f.Close()
// 获取文件的字节个数
var size int
if info, err := f.Stat(); err == nil {
size64 := info.Size()
if int64(int(size64)) == size64 {
size = int(size64)
}
}
size++ // one byte for final read at EOF
if size < 512 {
size = 512
}
// 直接将data设置为字节数+1的长度,下面直接修改每个元素
data := make([]byte, 0, size)
for {
if len(data) >= cap(data) {
d := append(data[:cap(data)], 0)
data = d[:len(data)]
}
n, err := f.Read(data[len(data):cap(data)])
data = data[:len(data)+n]
if err != nil {
if err == io.EOF {
err = nil
}
return data, err
}
}
}