Skip to content

Commit af7e4ac

Browse files
committed
util: add ReadFile function
1 parent 40a2dbe commit af7e4ac

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

util/util.go

+50
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,53 @@ func getUnderlyingAndPath(fs billy.Basic, path string) (billy.Basic, string) {
222222

223223
return u.Underlying(), path
224224
}
225+
226+
// ReadFile reads the named file and returns the contents from the given filesystem.
227+
// A successful call returns err == nil, not err == EOF.
228+
// Because ReadFile reads the whole file, it does not treat an EOF from Read
229+
// as an error to be reported.
230+
func ReadFile(fs billy.Basic, name string) ([]byte, error) {
231+
f, err := fs.Open(name)
232+
if err != nil {
233+
return nil, err
234+
}
235+
236+
defer f.Close()
237+
238+
var size int
239+
if info, err := fs.Stat(name); err == nil {
240+
size64 := info.Size()
241+
if int64(int(size64)) == size64 {
242+
size = int(size64)
243+
}
244+
}
245+
246+
size++ // one byte for final read at EOF
247+
// If a file claims a small size, read at least 512 bytes.
248+
// In particular, files in Linux's /proc claim size 0 but
249+
// then do not work right if read in small pieces,
250+
// so an initial read of 1 byte would not work correctly.
251+
252+
if size < 512 {
253+
size = 512
254+
}
255+
256+
data := make([]byte, 0, size)
257+
for {
258+
if len(data) >= cap(data) {
259+
d := append(data[:cap(data)], 0)
260+
data = d[:len(data)]
261+
}
262+
263+
n, err := f.Read(data[len(data):cap(data)])
264+
data = data[:len(data)+n]
265+
266+
if err != nil {
267+
if err == io.EOF {
268+
err = nil
269+
}
270+
271+
return data, err
272+
}
273+
}
274+
}

util/util_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,24 @@ func TestTempDir(t *testing.T) {
4141
}
4242
}
4343
}
44+
45+
func TestReadFile(t *testing.T) {
46+
fs := memfs.New()
47+
f, err := util.TempFile(fs, "", "")
48+
if err != nil {
49+
t.Fatal(err)
50+
}
51+
52+
f.Write([]byte("foo"))
53+
f.Close()
54+
55+
data, err := util.ReadFile(fs, f.Name())
56+
if err != nil {
57+
t.Fatal(err)
58+
}
59+
60+
if string(data) != "foo" || err != nil {
61+
t.Errorf("ReadFile(%q, %q) = %v, %v", fs, f.Name(), data, err)
62+
}
63+
64+
}

0 commit comments

Comments
 (0)