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 5package fs 6 7import "io" 8 9// ReadFileFS is the interface implemented by a file system 10// that provides an optimized implementation of [ReadFile]. 11type 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]. 32func 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