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 string) ([]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 := make([]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