Reading files is one of the most common tasks in everyday programmer’s work. You can do it in different ways depending on your needs. In this tutorial, we show you how to read the entire file at once, line by line, word by word, and in chunks. All of these methods are very simple in Go 🙂.
Read an entire file
The simplest way of reading a text or binary file in Go is to use the ReadFile()
function from the os
package. This function reads the entire content of the file into a byte slice, so you should be careful when trying to read a large file - in this case, you should read the file line by line or in chunks. For small files, this function is more than sufficient.
If you are using the Go version earlier than 1.16, you will find the
ReadFile()
function in theioutil
package.
package main
import (
"fmt"
"log"
"os"
)
func main() {
content, err := os.ReadFile("file.txt")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(content))
}
Output:
Hello World!
This is txt file read by Go!
Read a file line by line
To read a file line by line, we can use a convenient bufio.Scanner
structure. Its constructor, NewScanner()
, takes an opened file (remember to close the file after the operation is done, for example, by using defer
statement) and lets you read subsequent lines through Scan()
and Text()
methods. Using Err()
method, you can check errors encountered during file reading.
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
// open file
f, err := os.Open("file.txt")
if err != nil {
log.Fatal(err)
}
// remember to close the file at the end of the program
defer f.Close()
// read the file line by line using scanner
scanner := bufio.NewScanner(f)
for scanner.Scan() {
// do something with a line
fmt.Printf("line: %s\n", scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}
Output:
line: Hello World!
line: This is txt file read by Go!
Read a file word by word
Reading a file word by word is almost the same as reading line by line. You only need to change the split function of the Scanner
from the default ScanLines()
to ScanWords()
.
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
// open file
f, err := os.Open("file.txt")
if err != nil {
log.Fatal(err)
}
// remember to close the file at the end of the program
defer f.Close()
// read the file word by word using scanner
scanner := bufio.NewScanner(f)
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
// do something with a word
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}
Output:
Hello
World!
This
is
txt
file
read
by
Go!
Read a file in chunks
When you have a very large file or don’t want to store the entire file in memory, you can read the file in fixed-size chunks. In this case, you need to create a byte slice of the specified size (chunkSize
in the example) as a buffer for storing the subsequent read bytes. Using Read()
method of the File
type, we can load the next chunk of the file data. The reading loop finishes when an io.EOF
error occurs, indicating the end of the file.
package main
import (
"fmt"
"io"
"log"
"os"
)
const chunkSize = 10
func main() {
// open file
f, err := os.Open("file.txt")
if err != nil {
log.Fatal(err)
}
// remember to close the file at the end of the program
defer f.Close()
buf := make([]byte, chunkSize)
for {
n, err := f.Read(buf)
if err != nil && err != io.EOF {
log.Fatal(err)
}
if err == io.EOF {
break
}
fmt.Println(string(buf[:n]))
}
}
Output:
Hello Worl
d!
This is
txt file
read by Go
!