golang 文件操作
chenzuoqing Lv3

golang 文件操作

打开文件

在 golang 中,用 os.Open() 来打开文件,将返回一个文件实例 *File 和错误 err,文件实例调用 Close() 方法来关闭文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"fmt"
"os"
)

func main() {
// 打开文件
file, err := os.Open(filename)
defer file.Close() // 关闭文件
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
// 文件操作
}

写文件的打开方式又略有不同,需要另外指定参数,用 os.OpenFile() 打开,该方法签名如下,参数在后面写文件部分介绍

1
func OpenFile(name string, flag int, perm FileMode) (*File, error)

读取文件

读取文件有多种方式,速度可以测试一下再选用

  • File.Read 文件实例自带的操作
  • bufio 带缓冲的IO,速度快,读到内存中缓冲,发起读写操作时会先冲缓冲中获取数据
  • ioutil 重点是方便,里面一些操作有封装 bufio
    • ioutil.ReadAll
    • ioutil.Read

示例代码,分别是文件实例直接读取和循环、bufio 库读取、逐行读取、ioutil 库读取的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package main

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

// file.Read读取文件
func osReader(filename string) {
file, err := os.Open(filename)
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()

var content [32]byte
// 读取需要一个接收一个byte切片,返回读取数据的大小和错误
n, err := file.Read(content[:])
if err == io.EOF { // 文件结束时返回错误是EOF,n是0
fmt.Println("文件读完了!")
}
if err != nil {
fmt.Println("读取文件失败!")
}

fmt.Println(string(content[:n]))
}

// bufio 读取文件
func bufioReader(filename string) {
file, err := os.Open(filename)
if err != nil {
fmt.Println("打开文件失败:", err)
}
defer file.Close()
//reader := bufio.NewReader(file) // 默认大小
reader := bufio.NewReaderSize(file, 32) // 可以指定大小
content := make([]byte, 32)
n, err := reader.Read(content)
if err == io.EOF { // 文件结束时返回错误是EOF,n是0
fmt.Println("文件读完了!")
}
if err != nil {
fmt.Println("读取文件失败!err:", err)
}
fmt.Println(string(content[:n]))
}

// fileRead循环读取文件
func osReaderLoop(filename string) {
file, err := os.Open(filename)
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()

var content []byte
var tmp = make([]byte, 128)
for {
n, err := file.Read(tmp)
if err == io.EOF {
fmt.Println("文件读完了!")
break
}
if err != nil {
fmt.Println("读取文件失败!err:", err)
return
}
content = append(content, tmp[:n]...) // 追加到content中
}
fmt.Println(string(content))
}

// bufio逐行读取
func bufioReaderLine(filename string) {
file, err := os.Open(filename)
if err != nil {
fmt.Println("打开文件失败:", err)
}
defer file.Close()
reader := bufio.NewReader(file) // 默认大小
//var content []byte
for {
line, err := reader.ReadString('\n') // 指定定界符,读到该字符时返回一次,返回字符串
if err == io.EOF {
fmt.Println("文件读完了!")
break
}
if err != nil {
fmt.Println("读取文件失败!err:", err)
return
}
fmt.Print(line)
}
}

// ioutil读取文件
func ioutilReader(filename string) {
// 可以直接读取文件,代码中不用另外打开,返回byte切片和err
content, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Println("读取文件失败!err:", err)
return
}
fmt.Print(string(content)) // 转字符串打印
}

func main() {
filename := "./tmp.txt"
fmt.Println("file.Read:")
osReader(filename)

fmt.Println("bufio读取文件:")
bufioReader(filename)

fmt.Println("file.Read循环读取:")
osReaderLoop(filename)

fmt.Println("bufio循环读取:")
bufioReaderLine(filename)

fmt.Println("ioutil读取:")
ioutilReader(filename)
}

假设有文件 ./tmp.txt,内容如下:

1
2
3
4
5
hello world1!
hello world2!
hello world3!
hello world4!
hello world5!

运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
file.Read:
hello world1!
hello world2!
bufio读取文件:
hello world1!
hello world2!
file.Read循环读取:
文件读完了!
hello world1!
hello world2!
hello world3!
hello world4!
hello world5!
bufio循环读取:
hello world1!
hello world2!
hello world3!
hello world4!
文件读完了!

文件写入

需要写文件时,需要用 os.OpenFile() 指定操作模式打开文件,得到文件实例后进行写入,看下它的签名

  • filename 文件名
  • flag 是操作模式,在 os 包中有定义这些常量可以用,多个之间可以用 | 拼接
  • perm 指定文件权限,为一个八进制数,读写执行分别为(r : 04,w : 02,x : 01)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // flag常量定义的部分
    const (
    // Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.
    O_RDONLY int = syscall.O_RDONLY // open the file read-only.(只读)
    O_WRONLY int = syscall.O_WRONLY // open the file write-only.(只写)
    O_RDWR int = syscall.O_RDWR // open the file read-write.(可读可写)
    // The remaining values may be or'ed in to control behavior.
    O_APPEND int = syscall.O_APPEND // append data to the file when writing.(追加写)
    O_CREATE int = syscall.O_CREAT // create a new file if none exists.(不存在将创建)
    O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist.(与创建搭配使用,文件必须不存在)
    O_SYNC int = syscall.O_SYNC // open for synchronous I/O.(用同步IO,不写缓冲直接落盘)
    O_TRUNC int = syscall.O_TRUNC // truncate regular writable file when opened.(清空再写)
    )

    // OpenFile 函数签名
    func OpenFile(name string, flag int, perm FileMode) (*File, error)

写文件示例,可以看到 ioutil 是封装的比较方便使用,;另外 bufio 因为有缓冲,所以有个刷盘操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package main

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

//File实例的写入操作,将创建文件,并清空
func fileInstanceWriter(filename string, content string) {
// 注意若多次重复写入文件,又未指定os.O_TRUNC模式,将从文件开头写,覆盖旧内容
// 若旧内容比新内容长,覆盖了部分长度的内容,容易导致字符不完整
file, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()

_, err = file.Write([]byte(content)) // 返回写入的长度
//_, err = file.WriteString("测试写入文件!") // 写入字符串,方法内自动加了[]byte(s)
if err != nil {
fmt.Println("写入文件失败:", err)
return
}
}

// bufio写文件示例
func bufioWriter(filename string, content string) {
file, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()

writer := bufio.NewWriter(file)
if _, err = writer.WriteString(content); err != nil {
fmt.Println("写入文件失败:", err)
return
}
if err = writer.Flush(); err != nil { // 将缓存内容刷盘
fmt.Println("写入磁盘失败")
}
}

// ioutil写文件示例
func ioutilWriter(filename string, content string) {
if err := ioutil.WriteFile(filename, []byte(content), 0666); err != nil {
fmt.Println("写入文件失败:", err)
return
}
}

func main() {
fileInstanceWriter("./fileInstanceWriter.txt", "测试写入文件!")
bufioWriter("./bufioWriter.txt", "测试用bufio写入文件")
ioutilWriter("./ioutilWriter.txt", "测试用ioutil写入文件")
}

刚接触,备忘。

 Comments