github.com/3JoB/vfs@v1.0.0/ioutil.go (about)

     1  package vfs
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"os"
     7  )
     8  
     9  // WriteFile writes data to a file named by filename on the given Filesystem. If
    10  // the file does not exist, WriteFile creates it with permissions perm;
    11  // otherwise WriteFile truncates it before writing.
    12  //
    13  // This is a port of the stdlib ioutil.WriteFile function.
    14  func WriteFile(fs Filesystem, filename string, data []byte, perm os.FileMode) error {
    15  	f, err := fs.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
    16  	if err != nil {
    17  		return err
    18  	}
    19  	n, err := f.Write(data)
    20  	if err == nil && n < len(data) {
    21  		err = io.ErrShortWrite
    22  	}
    23  	if err1 := f.Close(); err == nil {
    24  		err = err1
    25  	}
    26  	return err
    27  }
    28  
    29  // ReadFile reads the file named by filename and returns the contents. A
    30  // successful call returns err == nil, not err == EOF. Because ReadFile reads
    31  // the whole file, it does not treat an EOF from Read as an error to be
    32  // reported.
    33  //
    34  // This is a port of the stdlib ioutil.ReadFile function.
    35  func ReadFile(fs Filesystem, filename string) ([]byte, error) {
    36  	f, err := fs.OpenFile(filename, os.O_RDONLY, 0)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  	defer f.Close()
    41  
    42  	// It's a good but not certain bet that FileInfo will tell us exactly how
    43  	// much to read, so let's try it but be prepared for the answer to be wrong.
    44  	var n int64
    45  	if fi, err := fs.Stat(filename); err == nil {
    46  		if size := fi.Size(); size < 1e9 {
    47  			n = size
    48  		}
    49  	}
    50  
    51  	// As initial capacity for readAll, use n + a little extra in case Size is
    52  	// zero, and to avoid another allocation after Read has filled the buffer.
    53  	// The readAll call will read into its allocated internal buffer cheaply. If
    54  	// the size was wrong, we'll either waste some space off the end or
    55  	// reallocate as needed, but in the overwhelmingly common case we'll get it
    56  	// just right.
    57  	return readAll(f, n+bytes.MinRead)
    58  }
    59  
    60  // readAll reads from r until an error or EOF and returns the data it read from
    61  // the internal buffer allocated with a specified capacity.
    62  //
    63  // This is a paste of the stdlib ioutil.readAll function.
    64  func readAll(r io.Reader, capacity int64) (b []byte, err error) {
    65  	buf := bytes.NewBuffer(make([]byte, 0, capacity))
    66  
    67  	// If the buffer overflows, we will get bytes.ErrTooLarge.
    68  	// Return that as an error. Any other panic remains.
    69  	defer func() {
    70  		e := recover()
    71  		if e == nil {
    72  			return
    73  		}
    74  		if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
    75  			err = panicErr
    76  		} else {
    77  			panic(e)
    78  		}
    79  	}()
    80  
    81  	_, err = buf.ReadFrom(r)
    82  	return buf.Bytes(), err
    83  }