How to read a file in Golang
Golang has many things into the standard library. One of those is a utility package to deal with I/O: ioutil. In order to read a file in Go we can use, amongst others, the ioutil.ReadFile
func ReadFile(filename string) ([]byte, error)
ReadFile reads the file named by filename and returns the contents. A successful call returns err == nil, not err == EOF. Because ReadFile reads the whole file, it does not treat an EOF from Read as an error to be reported.
Let’s see an example of this
package main
import (
"iotuil"
"fmt"
"log"
)
func main() {
body, err := iotuil.ReadFile("file.txt")
if err != nil {
log.Fatalf("unable to read file: %v", err)
}
fmt.Println(string(body))
}
Bear in mind that in this way we load the entire file contents into memory at once. All of it is in body
which is a slice of bytes.
If you want more flexibility around the way you read the file you should check out the os, specifically the os.Open function, which, given a string representing the file’s name returns a reference to a *File struct
func Open(name string) (*File, error)
Open opens the named file for reading. If successful, methods on the returned file can be used for reading; the associated file descriptor has mode O_RDONLY. If there is an error, it will be of type *PathError.
We are also going to be using File.Read
func (f *File) Read(b []byte) (n int, err error)
Read reads up to len(b) bytes from the File. It returns the number of bytes read and any error encountered. At end of file, Read returns 0, io.EOF.
Let’s see an example of how we can read a file using os.Open
package main
import (
"iotuil"
"fmt"
"log"
"io"
)
func main() {
f, err := os.Open("file.txt")
if err != nil {
log.Fatalf("unable to read file: %v", err)
}
defer f.Close()
buf := make([]byte, 1024)
for {
n, err := f.Read(buf)
if err == io.EOF {
break
}
if err != nil {
fmt.Println(err)
continue
}
if n > 0 {
fmt.Println(string(buf[:n]))
}
}
}
In the example above we read the file chunk by chunk, specifying which is the buffer size we want to read each time. Only len(buf)
is allocated in memory and read at each iteration. This is specifically ideal for large files, where content cannot fit entirely into memory. Notice how we break the loop once we receive an io.EOF
error, which defines the end of the file.