aboutsummaryrefslogtreecommitdiff
path: root/src/io/fs/readfile.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/io/fs/readfile.go')
-rw-r--r--src/io/fs/readfile.go63
1 files changed, 63 insertions, 0 deletions
diff --git a/src/io/fs/readfile.go b/src/io/fs/readfile.go
new file mode 100644
index 0000000000..7ee9eadac4
--- /dev/null
+++ b/src/io/fs/readfile.go
@@ -0,0 +1,63 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fs
+
+import "io"
+
+// ReadFileFS is the interface implemented by a file system
+// that provides an optimized implementation of ReadFile.
+type ReadFileFS interface {
+ FS
+
+ // ReadFile reads the named file and returns its contents.
+ // A successful call returns a nil error, not io.EOF.
+ // (Because ReadFile reads the whole file, the expected EOF
+ // from the final Read is not treated as an error to be reported.)
+ ReadFile(name string) ([]byte, error)
+}
+
+// ReadFile reads the named file from the file system fs and returns its contents.
+// A successful call returns a nil error, not io.EOF.
+// (Because ReadFile reads the whole file, the expected EOF
+// from the final Read is not treated as an error to be reported.)
+//
+// If fs implements ReadFileFS, ReadFile calls fs.ReadFile.
+// Otherwise ReadFile calls fs.Open and uses Read and Close
+// on the returned file.
+func ReadFile(fsys FS, name string) ([]byte, error) {
+ if fsys, ok := fsys.(ReadFileFS); ok {
+ return fsys.ReadFile(name)
+ }
+
+ file, err := fsys.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ var size int
+ if info, err := file.Stat(); err == nil {
+ size64 := info.Size()
+ if int64(int(size64)) == size64 {
+ size = int(size64)
+ }
+ }
+
+ data := make([]byte, 0, size+1)
+ for {
+ if len(data) >= cap(data) {
+ d := append(data[:cap(data)], 0)
+ data = d[:len(data)]
+ }
+ n, err := file.Read(data[len(data):cap(data)])
+ data = data[:len(data)+n]
+ if err != nil {
+ if err == io.EOF {
+ err = nil
+ }
+ return data, err
+ }
+ }
+}