Golang File Read: How To Read Files In Go

0
137
How To Read Files In Golang | Go File Read Example

Read files in Golang is one of the most common operations. Golang has an io/ioutil package that provides ReadFile() function. The ioutil.ReadFile() function reads an entire file into memory. We will use os, io, and bufio packages.

How To Read Files In Golang

We can read files in many ways in Go. Let’s list them all.

  1. Reading an entire file into memory (as we have discussed).
  2. Reading a file in small chunks
  3. Reading a file line by line

Let’s discuss these ways in-depth.

Reading an entire file into memory

Let’s read the file from the directory where our go program hello.go is located.

We have another file called test.txt, and in that file, the content is following.

Tomorrow The Rise Of Skywalker Will Release in India.
The Witcher will be also coming to Netflix.

So, we will read the above content using ioutil.ReadFile() function.

Okay, now write the following code inside the hello.go file. Remember the hello.go file is in the same directory as the test.txt file.

// hello.go

package main

import (
	"fmt"
	"io/ioutil"
)

func main() {
	data, err := ioutil.ReadFile("test.txt")
	if err != nil {
		fmt.Println("File reading error", err)
		return
	}
	fmt.Println("Contents of file:", string(data))
}

Output

go run hello.go
Contents of file: Tomorrow The Rise Of Skywalker Will Release in India.
The Witcher will be also coming to Netflix.

First, we have imported the required packages.

Then the program reads the file and returns a byte slice, which is stored in data. Then, we convert the data to a string and display the contents of the file.

If the above code is run from any other location, for instance, try running the program from /home/krunal/hello.go, it will log the following error in the console.

➜  hello go run hello.go
File reading error open /test.txt: no such file or directory
➜  hello

We got this error: File reading error open /test.txt: no such file or directory.

Because there is no hello.go file in that directory.

The reason is that Go is a compiled language. What Go install does is that it creates the binary from a source code.  A binary is independent of the source code; that is why it can be run from any location.

In the case of the test.txt file, it is not found in the location from which the binary is run; that is why the program complains that it cannot find the file it specified.

There are two ways to solve this problem,

  1. Using an absolute file path.
  2. Passing the file path as a command-line flag.

Let’s discuss them one by one.

Using an absolute file path

The correct way to do it is to pass an absolute file path in the Go program.

If you do not know what your current path is, then you can type the following command on your terminal. It will work on Mac and Linux.

➜  hello pwd
/Users/krunal/Desktop/code/go/src/hello

So, I am in the hello directory.

Now, in the above example, let’s write the above path and then filename and see the output.

// hello.go

package main

import (
	"fmt"
	"io/ioutil"
)

func main() {
	data, err := ioutil.ReadFile("/Users/krunal/Desktop/code/go/src/hello/test.txt")
	if err != nil {
		fmt.Println("File reading error", err)
		return
	}
	fmt.Println("Contents of file:", string(data))
}

Output

➜  hello go run hello.go
Contents of file: Tomorrow The Rise Of Skywalker Will Release in India.
The Witcher will be also coming to Netflix.
➜  hello

Passing the file path as a command-line flag.

Another way to solve the path problem is to pass a file path as a command-line flag.

Using the flag, we can get a file path as input from a command line and then read its contents. 

But first, let’s understand how the flag package works.

The flag package in Golang has a String function. This function accepts three arguments. The first argument is the flag’s name, the second argument is a default value, and the third argument is the short description of the flag.

Write the final code inside the hello.go that reads the file.

// hello.go

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
)

func main() {
	fptr := flag.String("fpath", "test.txt", "file path to read from")
	flag.Parse()
	data, err := ioutil.ReadFile(*fptr)
	if err != nil {
		fmt.Println("File reading error", err)
		return
	}
	fmt.Println("Contents of file:", string(data))
}

Output

➜  hello go run hello.go  -fpath=/Users/krunal/Desktop/code/go/src/hello/test.txt
Contents of file: Tomorrow The Rise Of Skywalker Will Release in India.
The Witcher will be also coming to Netflix.
➜  hello

In the first line, we have imported all the packages.

Then we have created the string flag named fpath with a default value test.txt and description file path to read from using a String function. Thie String function returns the address of a string variable that stores the value of a flag.

The flag.Parse() should be called before the program accesses any flag.

Then it reads the content of the file path passed from the command line.

How to read a file in small chunks in Golang

Until now, we learned how to load an entire file into memory and read the file.

When the file size is enormous(huge), it doesn’t make sense to read an entire file into memory, especially if you are running low on RAM.

To resolve this problem, the more optimal solution is to read a file in small chunks. This can be done by using the bufio package.

Let’s write a program that reads our test.txt file in chunks of 8 bytes.

Write the following code inside the hello.go file.

// hello.go

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
)

func main() {
	path := "test.txt"

	buf, err := os.Open(path)
	if err != nil {
		log.Fatal(err)
	}

	defer func() {
		if err = buf.Close(); err != nil {
			log.Fatal(err)
		}
	}()

	r := bufio.NewReader(buf)
	b := make([]byte, 8)
	for {
		n, err := r.Read(b)
		if err != nil {
			fmt.Println("Error reading file:", err)
			break
		}
		fmt.Println(string(b[0:n]))
	}
}

Output

➜  hello go run hello.go
Tomorrow
 The Ris
e Of Sky
walker W
ill Rele
ase in I
ndia.
Error reading file: EOF
➜  hello

In the above program, first, we have imported the required packages. Then we have opened a file, and then we defer the file closing.

In the next step, we are creating a new buffered reader.  We are using the bufio.NewReader() function to create a buffered reader. In the next step, we created a byte slice of length and capacity 8 into which the bytes of the file will be read.

A Read() method reads up to len(b) bytes, i.e., up to 8 bytes, and returns the number of bytes read.

We store the bytes returned in a variable. Then the slice is read from index 0 to n-1, i.e., up to the number of bytes returned by the Read() method and printed.

Once the file is reached in the end, it will return an EOF error. The rest of the program is self-explanatory.

How to read a file line by line in Golang

Now, let’s discuss how to read a file line by line in Go. This can be done using the bufio package.

Please replace the following contents in the test.txt file.

Tomorrow The Rise Of Skywalker Will Release in India.
The Witcher will be also coming to Netflix.
Last episode of The Mandalorian will air on 27th december.

Now, write the following code in hello.go file.

// hello.go

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
)

func main() {
	path := "test.txt"

	buf, err := os.Open(path)
	if err != nil {
		log.Fatal(err)
	}

	defer func() {
		if err = buf.Close(); err != nil {
			log.Fatal(err)
		}
	}()

	snl := bufio.NewScanner(buf)
	for snl.Scan() {
		fmt.Println(snl.Text())
	}
	err = snl.Err()
	if err != nil {
		log.Fatal(err)
	}
}

As usual, first, we have imported the required packages.

Then we opened a text.txt file.

Then we create a new scanner using the file. The scan() method reads the next line of the file, available through the text() method.

After Scan returns false, the Err() method will return any error that occurred during scanning. If the error is End of File, Err() will return nil.

Output

➜  hello go run hello.go
Tomorrow The Rise Of Skywalker Will Release in India.
The Witcher will be also coming to Netflix.
Last episode of The Mandalorian will air on 27th december.
➜  hello

Conclusion

In this tutorial, we have seen how to read a file in memory, line by line, and read a file in chunks.

Finally, How To Read Files In Golang Example Tutorial is over.

See also

How to create a file in Golang

How to open a file in Golang

How to write a file in Golang

How to delete a file in Golang

Leave A Reply

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.