/
gfile_contents.go
218 lines (195 loc) · 7.23 KB
/
gfile_contents.go
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/bjxujiang/gf.
package gfile
import (
"bufio"
"io"
"io/ioutil"
"os"
"github.com/bjxujiang/gf/util/gconv"
)
var (
// Buffer size for reading file content.
DefaultReadBuffer = 1024
)
// GetContents returns the file content of <path> as string.
// It returns en empty string if it fails reading.
func GetContents(path string) string {
return gconv.UnsafeBytesToStr(GetBytes(path))
}
// GetBytes returns the file content of <path> as []byte.
// It returns nil if it fails reading.
func GetBytes(path string) []byte {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil
}
return data
}
// putContents puts binary content to file of <path>.
func putContents(path string, data []byte, flag int, perm os.FileMode) error {
// It supports creating file of <path> recursively.
dir := Dir(path)
if !Exists(dir) {
if err := Mkdir(dir); err != nil {
return err
}
}
// Opening file with given <flag> and <perm>.
f, err := OpenWithFlagPerm(path, flag, perm)
if err != nil {
return err
}
defer f.Close()
if n, err := f.Write(data); err != nil {
return err
} else if n < len(data) {
return io.ErrShortWrite
}
return nil
}
// Truncate truncates file of <path> to given size by <size>.
func Truncate(path string, size int) error {
return os.Truncate(path, int64(size))
}
// PutContents puts string <content> to file of <path>.
// It creates file of <path> recursively if it does not exist.
func PutContents(path string, content string) error {
return putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, DefaultPermOpen)
}
// PutContentsAppend appends string <content> to file of <path>.
// It creates file of <path> recursively if it does not exist.
func PutContentsAppend(path string, content string) error {
return putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_APPEND, DefaultPermOpen)
}
// PutBytes puts binary <content> to file of <path>.
// It creates file of <path> recursively if it does not exist.
func PutBytes(path string, content []byte) error {
return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, DefaultPermOpen)
}
// PutBytesAppend appends binary <content> to file of <path>.
// It creates file of <path> recursively if it does not exist.
func PutBytesAppend(path string, content []byte) error {
return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_APPEND, DefaultPermOpen)
}
// GetNextCharOffset returns the file offset for given <char> starting from <start>.
func GetNextCharOffset(reader io.ReaderAt, char byte, start int64) int64 {
buffer := make([]byte, DefaultReadBuffer)
offset := start
for {
if n, err := reader.ReadAt(buffer, offset); n > 0 {
for i := 0; i < n; i++ {
if buffer[i] == char {
return int64(i) + offset
}
}
offset += int64(n)
} else if err != nil {
break
}
}
return -1
}
// GetNextCharOffsetByPath returns the file offset for given <char> starting from <start>.
// It opens file of <path> for reading with os.O_RDONLY flag and default perm.
func GetNextCharOffsetByPath(path string, char byte, start int64) int64 {
if f, err := OpenWithFlagPerm(path, os.O_RDONLY, DefaultPermOpen); err == nil {
defer f.Close()
return GetNextCharOffset(f, char, start)
}
return -1
}
// GetBytesTilChar returns the contents of the file as []byte
// until the next specified byte <char> position.
//
// Note: Returned value contains the character of the last position.
func GetBytesTilChar(reader io.ReaderAt, char byte, start int64) ([]byte, int64) {
if offset := GetNextCharOffset(reader, char, start); offset != -1 {
return GetBytesByTwoOffsets(reader, start, offset+1), offset
}
return nil, -1
}
// GetBytesTilCharByPath returns the contents of the file given by <path> as []byte
// until the next specified byte <char> position.
// It opens file of <path> for reading with os.O_RDONLY flag and default perm.
//
// Note: Returned value contains the character of the last position.
func GetBytesTilCharByPath(path string, char byte, start int64) ([]byte, int64) {
if f, err := OpenWithFlagPerm(path, os.O_RDONLY, DefaultPermOpen); err == nil {
defer f.Close()
return GetBytesTilChar(f, char, start)
}
return nil, -1
}
// GetBytesByTwoOffsets returns the binary content as []byte from <start> to <end>.
// Note: Returned value does not contain the character of the last position, which means
// it returns content range as [start, end).
func GetBytesByTwoOffsets(reader io.ReaderAt, start int64, end int64) []byte {
buffer := make([]byte, end-start)
if _, err := reader.ReadAt(buffer, start); err != nil {
return nil
}
return buffer
}
// GetBytesByTwoOffsetsByPath returns the binary content as []byte from <start> to <end>.
// Note: Returned value does not contain the character of the last position, which means
// it returns content range as [start, end).
// It opens file of <path> for reading with os.O_RDONLY flag and default perm.
func GetBytesByTwoOffsetsByPath(path string, start int64, end int64) []byte {
if f, err := OpenWithFlagPerm(path, os.O_RDONLY, DefaultPermOpen); err == nil {
defer f.Close()
return GetBytesByTwoOffsets(f, start, end)
}
return nil
}
// ReadLines reads file content line by line, which is passed to the callback function <callback> as string.
// It matches each line of text, separated by chars '\r' or '\n', stripped any trailing end-of-line marker.
//
// Note that the parameter passed to callback function might be an empty value, and the last non-empty line
// will be passed to callback function <callback> even if it has no newline marker.
func ReadLines(file string, callback func(text string) error) error {
f, err := os.Open(file)
if err != nil {
return err
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
if err = callback(scanner.Text()); err != nil {
return err
}
}
return nil
}
// ReadByteLines reads file content line by line, which is passed to the callback function <callback> as []byte.
// It matches each line of text, separated by chars '\r' or '\n', stripped any trailing end-of-line marker.
//
// Note that the parameter passed to callback function might be an empty value, and the last non-empty line
// will be passed to callback function <callback> even if it has no newline marker.
//
// Deprecated, use ReadLinesBytes instead.
func ReadByteLines(file string, callback func(bytes []byte) error) error {
return ReadLinesBytes(file, callback)
}
// ReadLinesBytes reads file content line by line, which is passed to the callback function <callback> as []byte.
// It matches each line of text, separated by chars '\r' or '\n', stripped any trailing end-of-line marker.
//
// Note that the parameter passed to callback function might be an empty value, and the last non-empty line
// will be passed to callback function <callback> even if it has no newline marker.
func ReadLinesBytes(file string, callback func(bytes []byte) error) error {
f, err := os.Open(file)
if err != nil {
return err
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
if err = callback(scanner.Bytes()); err != nil {
return err
}
}
return nil
}