Reading files is one of the most essential tasks in programming. It allows us to see content, modify and write it using programming. In this post, we will see how to read file contents in Go.
1. Open a file for reading
The first step is to open the file for reading. We can use the os package Open()
function to open the file.
file, err := os.Open("filename.extension")
We also must make sure the file is closed after the operation is done. So, we can use the defer keyword to send the function execution at last.
defer file.Close() // closes the file after everything is done
Every operation that we do happens between open and close operations.
2. Getting File stats in Golang
We can get some stats about the file we are going to use. To get that we use the Stat() function. It returns a FileInfo object, which is an interface.
f, err := os.Open("filename.txt")
if err != nil {
fmt.Println(err)
}
fmt.Println(f.Stat())
// &{text.txt 32 {2069112024 30791177} {2125463227 30791181} {228393948
30791181} 0 20 0 1 {0 0} 2964374070 524288 264394 false} <nil>
As you can see multiple stat inside a FileInfo interface is returned by the stat function.
3. Reading a file in Golang
There are many ways to read a file. Here we will explore some of the common and effective ways to read a file in Go.
3.1 Load it entirely and read the file
This is a really straightforward way to read a file. Although it is not an efficient way when handling large files, it is pretty easy to do. So, for small files, it will work fine without creating any performance bottleneck. We have a file in the local directory called “text.txt”. It contains a string "This is some content"
. We want to read it.
We will use ioutil to read the file directly. The ioutil package makes sure that the file gets closed after reading. So, we don’t need to worry about the memory leakage due to not closing the file. Below is the implementation of how to use it.
package main
import (
"fmt"
"io/ioutil"
)
func main() {
content, err := ioutil.ReadFile("text.txt") // the file is inside the local directory
if err != nil {
fmt.Println("Err")
}
fmt.Println(string(content)) // This is some content
}
As you can see we need to convert it to a string after getting the content.
3.2 Read file by chunks
A more efficient approach when reading a file is to read it by chunks. That means we don’t take it all completely in memory but instead we load it by chunking. It’s very important to read large files in chunk to avoid out of memory errors.
package main
import (
"fmt"
"io"
"os"
)
func main() {
file, err := os.Open("text.txt")
if err != nil {
fmt.Println("Error opening file!!!")
}
defer file.Close()
// declare chunk size
const maxSz = 4
// create buffer
b := make([]byte, maxSz)
for {
// read content to buffer
readTotal, err := file.Read(b)
if err != nil {
if err != io.EOF {
fmt.Println(err)
}
break
}
fmt.Println(string(b[:readTotal])) // print content from buffer
}
}
This produces output as shown below when we use a long string.
3.3 Read file line by line
The bufio package has many great features of reading a file. Here is an example of reading a file line by line.
package main
import (
"fmt"
"os"
"bufio"
)
func main() {
file, err := os.Open("text.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
fmt.Println(err)
}
}
It checks for the presence of a newline (‘\n’) character and splits it accordingly.
3.4 Read file word by word
The ScanWords from the bufio package can be used read a file word by word.
package main
import (
"fmt"
"os"
"bufio"
)
func main() {
file, err := os.Open("text.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanWords) // use scanwords
for scanner.Scan() {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
fmt.Println(err)
}
}
And here is the output:
These are some of the most common and frequently used ways to read a file in the Go programming language.