// 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.) // // The caller is permitted to modify the returned byte slice. // This method should return a copy of the underlying data. 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 } } }