#Reading And Writing To Files in Go
Note - If you are interested in working with JSON in Go, you may also like my other tutorial - Go JSON Tutorial
Within this tutorial, we are going to look at how you can effectively read and write to files within your filesystem using the go programming language.
The method we are going to use to read and write to these files will be file
format-agnostic. What this means is that you’ll be able to use the techniques
we’ll be covering in order to read and write, .txt, .csv, .xls and so on,
the only thing that differs for these files is the structure of the data that
you write to each of these file types.
Reading Files
In order to read from files on your local filesystem, you’ll have to use the
os package. You’ll first have to pull the contents of a file into
memory by calling os.ReadFile("/path/to/my/file.ext") which will take in
the path to the file you wish to read in as its only parameter. This will
return either the data of the file, or an err which can be handled as you
normally handle errors in Go.
Create a new file called main.go as well as another file called
localfile.data. Add a random piece of text to the .data file so that our
finished go program has something to read and then do the following:
package main
import (
"fmt"
"log"
"os"
)
func main() {
// read in the contents of the localfile.data
data, err := os.ReadFile("localfile.data")
if err != nil {
log.Fatal(err)
}
// print out the contents as a string
fmt.Print(string(data))
}
Once you have added this go code to your main.go file, try running it by
calling:
> go run main.go
this has all my content%
As you can see, we’ve successfully managed to read all of the data stored within
our proprietary localfile.data file type.
Writing Files to New Files
Now that we’ve covered reading from files in Go, it’s time to look at creating and writing to our own files!
In order to write content to files using Go, we’ll use the os package.
We’ll first have to construct a byte array that represents the content we
wish to store within our files.
mydata := []byte("all my data I want to write to a file")
Once we have constructed this byte array, we can then call os.WriteFile()
to write this byte array to a file. The WriteFile() function takes in 3
different parameters: the file path, the data to write, and the FileMode,
which represents the file’s permission bits.
// WriteFile creates the file and returns an error if unsuccessful
err := os.WriteFile("myfile.data", mydata, 0644)
if err != nil {
log.Fatal(err)
}
Let’s expand our original main.go file to not only read, but to write to a
file as well:
package main
import (
"fmt"
"log"
"os"
)
func main() {
mydata := []byte("All the data I wish to write to a file")
// WriteFile creates the file and returns an error if unsuccessful
err := os.WriteFile("myfile.data", mydata, 0644)
if err != nil {
log.Fatal(err)
}
data, err := os.ReadFile("myfile.data")
if err != nil {
log.Fatal(err)
}
fmt.Print(string(data))
}
If you attempt to run this now by calling go run main.go, you should see that
a new file is automatically created within your current directory called
myfile.data and our go program proceeds to read from this newly created file
and prints the contents in the console:
➜ go run main.go
All the data I wish to write to a file
Writing to Existing Files
What happens if we have an existing file that we want to write additional information to?
Let’s take a look at that now.
package main
import (
"fmt"
"log"
"os"
)
func main() {
mydata := []byte("All the data I wish to write to a file\n")
// WriteFile creates the file and returns an error if unsuccessful
err := os.WriteFile("myfile.data", mydata, 0644)
if err != nil {
log.Fatal(err)
}
data, err := os.ReadFile("myfile.data")
if err != nil {
log.Fatal(err)
}
fmt.Print(string(data))
f, err := os.OpenFile("myfile.data", os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer f.Close()
if _, err = f.WriteString("new data that wasn't there originally\n"); err != nil {
log.Fatal(err)
}
data, err = os.ReadFile("myfile.data")
if err != nil {
log.Fatal(err)
}
fmt.Print(string(data))
}
Now that you have added the new code, we can test it out by running our
main.go file:
$ go run main.go
All the data I wish to write to a file
new data that wasn't there originally
And Voila! We have successfully managed to append to an existing file using
os.OpenFile and the f.WriteString() method.
File Permissions
It’s incredibly important to understand the various different file permissions available to you when you are writing to new files.
Note - For more in-depth documentation about permissions, I would suggest checking out: https://golang.org/pkg/os/#FileMode
Conclusion
If you understand the basics of reading and writing files in Go, then you have the basics down for reading and writing any filetype possible, be that CSV, PNG or some proprietary data format. All you need to know, is how this data is structured so that you can parse and modify to suit your needs.
That’s all we are going to cover in this tutorial, we’ve managed to look at reading and writing to a really simple data format. We then briefly looked at file permissions.
Further Reading:
- Parsing JSON Files with Go
- Parsing XML Files with Go
- Go JSON Tutorial
- Error Handling in Go
- Reading and Writing Files - Quick Reference
- Checking if a File Exists
- Getting File Info
Hopefully you found this tutorial useful, if you did, or if you require further help, then please do not hesitate to let me know in the comments section below!
Continue Learning
Working with Temporary Files and Directories in Go 1.11
In this tutorial, we are going to be looking at how you can create and work with temp files and directories in Go 1.11
Go Graphql Beginners Tutorial - Part 2
In this tutorial, we are going to be taking a more in-depth look at GraphQL and how you can use it within your Go programs
Go GraphQL Beginners Tutorial
In this tutorial, we are going to be looking at how you can work with GraphQL in our Go programs.
An Introduction to Go Closures - Tutorial
In this tutorial, we are going to be looking at closures and how you can use them within your own Go applications.