| // 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 |
| } |
| } |
| } |