golang中文件读取的多种姿势

在golang中有多种文件读取的方式,这里自己做了个总结,可以根据自己的喜好合理选择。 总结来说,主要就是如下几种:

  • 实现io.Reader接口的对象r,调用对应的r.Read()方法
  • 实现io.Reader接口的对象r,传入io.ReadFull()方法,进行读取
  • 使用”io/ioutil” 提供的ioutil.ReadAll()方法
  • 使用”bufio”包提供的基于缓冲区的io.Reader接口实现,进行文件读取

姿势1

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
//BasicFileRead 内部使用Reader.Read()循环调用来实现文件读取
// os.Open返回的文件描述符实现了Reader接口
func BasicFileRead(path string, onceBufLen int) []byte {
//注意,os.Open打开的文件描述符 mode为O_RDONLY,
//如果需要其他更多读写权限,需要直接调用os.OpenFile
file, err := os.Open(path)
if err != nil {
fmt.Println("err:", err)
}
defer file.Close()

chunks := make([]byte, 0)
for {
buf := make([]byte, onceBufLen)
n, err := file.Read(buf)
if err != nil {
if err != io.EOF {
panic("file read error")
}
}

chunks = append(chunks, buf[:n]...)
if err == io.EOF {
break
}
}
return chunks
}

// 姿势1的变种
//BasicIORead 将文件描述符转换为一个io.Reader对象,然后进行循环操作,读取全部文件内容并返回
func BasicIORead(path string, onceBufLen int) []byte {
//注意,os.Open打开的文件描述符 mode为O_RDONLY,
//如果需要其他更多读写权限,需要直接调用os.OpenFile
file, err := os.Open(path)
if err != nil {
fmt.Println("err:", err)
}
defer file.Close()

var r io.Reader

r = file

chunks := make([]byte, 0)
for {
buf := make([]byte, onceBufLen)
n, err := r.Read(buf)
if err != nil {
if err != io.EOF {
panic("file read error")
}
}

chunks = append(chunks, buf[:n]...)
if err == io.EOF {
break
}
}
return chunks
}

姿势2

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
//BasicIOReadfull 内部使用io.ReadFull 循环调用去处理文件读取
func BasicIOReadfull(path string, onceBufLen int) []byte {
//注意,os.Open打开的文件描述符 mode为O_RDONLY,
//如果需要其他更多读写权限,需要直接调用os.OpenFile
file, err := os.Open(path)
if err != nil {
fmt.Println("err:", err)
}
defer file.Close()

chunks := make([]byte, 0)
for {
buf := make([]byte, onceBufLen)

n, err := io.ReadFull(file, buf)
if err != nil {
if err != io.ErrUnexpectedEOF && err != io.EOF {
fmt.Println("readall error:", err)
}
}
chunks = append(chunks, buf[:n]...)

if err == io.ErrUnexpectedEOF || err == io.EOF {
// fmt.Println("break.....", err)
break
}
}

file.Close()
// fmt.Println("chunks len:::", len(chunks))
return chunks
}

姿势3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//IOUtilReadall 使用io/ioutil包提供的ioutil.ReadAll方法,去读取全部的文件内容
// 目前来说,这个应该是最简洁的一种方式
func IOUtilReadall(path string) []byte {
//注意,os.Open打开的文件描述符 mode为O_RDONLY,
//如果需要其他更多读写权限,需要直接调用os.OpenFile
file, err := os.Open(path)
if err != nil {
fmt.Println("err:", err)
}
defer file.Close()

chunks, err := ioutil.ReadAll(file)
if err != nil && err != io.EOF {
panic("file read error")
}

return chunks
}

姿势4

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
//BufIORead 使用基于缓冲区的读写进行文件读取
func BufIORead(path string, onceBufLen int) []byte {
//注意,os.Open打开的文件描述符 mode为O_RDONLY,
//如果需要其他更多读写权限,需要直接调用os.OpenFile
file, err := os.Open(path)
if err != nil {
fmt.Println("err:", err)
}
defer file.Close()

// 如果想手动指定缓冲区大小,可调用NewReaderSize(), 默认缓冲区大小4096byte
r := bufio.NewReader(file)

chunks := make([]byte, 0)
for {
buf := make([]byte, onceBufLen)
n, err := r.Read(buf)
if err != nil {
if err != io.EOF {
panic("file read error")
}
}

chunks = append(chunks, buf[:n]...)
if err == io.EOF {
break
}
}
return chunks
}

完整代码

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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package main

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

func main() {

// size := os.Getpagesize()

// fmt.Println("size:", size)
// basicFileRead("../doc.md")
filepath := "../filetest"
b := make([]byte, 0)
// b = BasicIOReadfull(filepath, 9)
// b = BasicFileRead(filepath, 9)
// b = IOUtilReadall(filepath)
// b = BasicIORead(filepath, 100)
b = BufIORead(filepath, 100)

fmt.Println(string(b))
fmt.Println("file len:::", len(b))

}

//BasicFileRead 内部使用Reader.Read()循环调用来实现文件读取
// os.Open返回的文件描述符实现了Reader接口
func BasicFileRead(path string, onceBufLen int) []byte {
//注意,os.Open打开的文件描述符 mode为O_RDONLY,
//如果需要其他更多读写权限,需要直接调用os.OpenFile
file, err := os.Open(path)
if err != nil {
fmt.Println("err:", err)
}
defer file.Close()

chunks := make([]byte, 0)
for {
buf := make([]byte, onceBufLen)
n, err := file.Read(buf)
if err != nil {
if err != io.EOF {
panic("file read error")
}
}

chunks = append(chunks, buf[:n]...)
if err == io.EOF {
break
}
}
return chunks
}

//BasicIORead 将文件描述符转换为一个io.Reader对象,然后进行循环操作,读取全部文件内容并返回
func BasicIORead(path string, onceBufLen int) []byte {
//注意,os.Open打开的文件描述符 mode为O_RDONLY,
//如果需要其他更多读写权限,需要直接调用os.OpenFile
file, err := os.Open(path)
if err != nil {
fmt.Println("err:", err)
}
defer file.Close()

var r io.Reader

r = file

chunks := make([]byte, 0)
for {
buf := make([]byte, onceBufLen)
n, err := r.Read(buf)
if err != nil {
if err != io.EOF {
panic("file read error")
}
}

chunks = append(chunks, buf[:n]...)
if err == io.EOF {
break
}
}
return chunks
}

//BasicIOReadfull 内部使用io.ReadFull 循环调用去处理文件读取
func BasicIOReadfull(path string, onceBufLen int) []byte {
//注意,os.Open打开的文件描述符 mode为O_RDONLY,
//如果需要其他更多读写权限,需要直接调用os.OpenFile
file, err := os.Open(path)
if err != nil {
fmt.Println("err:", err)
}
defer file.Close()

chunks := make([]byte, 0)
for {
buf := make([]byte, onceBufLen)

n, err := io.ReadFull(file, buf)
if err != nil {
if err != io.ErrUnexpectedEOF && err != io.EOF {
fmt.Println("readall error:", err)
}
}
chunks = append(chunks, buf[:n]...)

if err == io.ErrUnexpectedEOF || err == io.EOF {
// fmt.Println("break.....", err)
break
}
}

file.Close()
// fmt.Println("chunks len:::", len(chunks))
return chunks
}

//IOUtilReadall 使用io/ioutil包提供的ioutil.ReadAll方法,去读取全部的文件内容
// 目前来说,这个应该是最简洁的一种方式
func IOUtilReadall(path string) []byte {
//注意,os.Open打开的文件描述符 mode为O_RDONLY,
//如果需要其他更多读写权限,需要直接调用os.OpenFile
file, err := os.Open(path)
if err != nil {
fmt.Println("err:", err)
}
defer file.Close()

// 这样可能存在的问题就是文件太大,把内存打爆
chunks, err := ioutil.ReadAll(file)
if err != nil && err != io.EOF {
panic("file read error")
}

return chunks
}

//BufIORead 使用基于缓冲区的读写进行文件读取
func BufIORead(path string, onceBufLen int) []byte {
//注意,os.Open打开的文件描述符 mode为O_RDONLY,
//如果需要其他更多读写权限,需要直接调用os.OpenFile
file, err := os.Open(path)
if err != nil {
fmt.Println("err:", err)
}
defer file.Close()

// 如果想手动指定缓冲区大小,可调用NewReaderSize(), 默认缓冲区大小4096byte
r := bufio.NewReader(file)

chunks := make([]byte, 0)
for {
buf := make([]byte, onceBufLen)
n, err := r.Read(buf)
if err != nil {
if err != io.EOF {
panic("file read error")
}
}

chunks = append(chunks, buf[:n]...)
if err == io.EOF {
break
}
}
return chunks
}

自己实现一个去除空格的文件读取对象

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
package main

import (
"fmt"
"io"
"os"
)

func main() {

fd, _ := os.Open("./test.txt")

r := NewTrimReader(fd)

chunks := make([]byte, 0)
for {
buf := make([]byte, r.onceReadLen)
n, err := r.Read(buf)
if err != nil {
if err != io.EOF {
panic("file read error")
}
}

chunks = append(chunks, buf[:n]...)
if err == io.EOF {
break
}
}
// 打印去除空格后的完整文件内容
fmt.Println("total file:", string(chunks))
}

type TrimReader struct {
reader io.Reader
onceReadLen int
}

func (t *TrimReader) Read(p []byte) (int, error) {

n, err := t.reader.Read(p)
if err != nil && err != io.EOF {
return n, err
}

newp := make([]byte, 0)
for _, v := range p[0:n] {
// 如果读取到空格,则忽略
if v == ' ' {
continue
}
newp = append(newp, v)
}
newcount := copy(p, newp)

return newcount, err
}

func NewTrimReader(r io.Reader) *TrimReader {
return &TrimReader{
reader: r,
onceReadLen: 100, //默认一次读取100byte
}
}

参考:
1.Golang学习 - io/ioutil 包
2.Golang学习 - io 包
3.GO语言基础进阶教程:bufio包