1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 package fs
6 7 import "io"
8 9 // ReadFileFS is the interface implemented by a file system
10 // that provides an optimized implementation of [ReadFile].
11 type ReadFileFS interface {
12 FS
13 14 // ReadFile reads the named file and returns its contents.
15 // A successful call returns a nil error, not io.EOF.
16 // (Because ReadFile reads the whole file, the expected EOF
17 // from the final Read is not treated as an error to be reported.)
18 //
19 // The caller is permitted to modify the returned byte slice.
20 // This method should return a copy of the underlying data.
21 ReadFile(name string) ([]byte, error)
22 }
23 24 // ReadFile reads the named file from the file system fs and returns its contents.
25 // A successful call returns a nil error, not [io.EOF].
26 // (Because ReadFile reads the whole file, the expected EOF
27 // from the final Read is not treated as an error to be reported.)
28 //
29 // If fs implements [ReadFileFS], ReadFile calls fs.ReadFile.
30 // Otherwise ReadFile calls fs.Open and uses Read and Close
31 // on the returned [File].
32 func ReadFile(fsys FS, name []byte) ([]byte, error) {
33 if fsys, ok := fsys.(ReadFileFS); ok {
34 return fsys.ReadFile(name)
35 }
36 37 file, err := fsys.Open(name)
38 if err != nil {
39 return nil, err
40 }
41 defer file.Close()
42 43 var size int
44 if info, err := file.Stat(); err == nil {
45 size64 := info.Size()
46 if int64(int(size64)) == size64 {
47 size = int(size64)
48 }
49 }
50 51 data := []byte{:0:size+1}
52 for {
53 if len(data) >= cap(data) {
54 d := append(data[:cap(data)], 0)
55 data = d[:len(data)]
56 }
57 n, err := file.Read(data[len(data):cap(data)])
58 data = data[:len(data)+n]
59 if err != nil {
60 if err == io.EOF {
61 err = nil
62 }
63 return data, err
64 }
65 }
66 }
67