Writing files is one of the most common operations in Go. In this article, we will learn about the different possibilities Go offers for doing so.
The article is divided into several sections:
If you are new to the world of Go, I recommend the following previous articles:
- Go basics
- Go functions
- Go unit tests
- Go pointers
- Go interfaces
- Go structs
- Go generics
- Go errors
- Go routines
- Go strings, chars, and runes
- Go defer
- Go first class functions
- Go reflection
- Go reading files
Write a string:
The code is quite self-explanatory.
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Create("test.txt")
if err != nil {
fmt.Println(err)
return
}
l, err := f.WriteString("Hello World\n")
if err != nil {
fmt.Println(err)
f.Close()
return
}
fmt.Println(l, "bytes written successfully")
err = f.Close()
if err != nil {
fmt.Println(err)
return
}
}
12 bytes written successfully
cat test.txt
Hello World
Write bytes:
Writing a sequence of bytes is very similar to the previous example; you just need to create the byte slice and write it.
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Create("test.txt")
if err != nil {
fmt.Println(err)
return
}
d2 := []byte{72, 101, 108, 108, 111, 32, 66, 121, 116, 101, 115, 10}
n2, err := f.Write(d2)
if err != nil {
fmt.Println(err)
f.Close()
return
}
fmt.Println(n2, "bytes written successfully")
err = f.Close()
if err != nil {
fmt.Println(err)
return
}
}
12 bytes written successfully
cat test.txt
Hello Bytes
Write line by line:
To write line by line, we will create a slice with each of the lines and write them using the fmt.Fprintln()
function, which takes the file descriptor as the first input parameter and the line to write as the second parameter.
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Create("test.txt")
if err != nil {
fmt.Println(err)
f.Close()
return
}
d := []string{"Welcome to the world of Go1.", "Go is a compiled language.", "It is easy to learn Go."}
for _, v := range d {
fmt.Fprintln(f, v)
if err != nil {
fmt.Println(err)
return
}
}
err = f.Close()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("File written successfully")
}
File written successfully
cat test.txt
Welcome to the world of Go1.
Go is a compiled language.
It is easy to learn Go.
Append content:
To append content to a previously existing file, you should not use the os.Create()
function but instead os.OpenFile()
. You must specify the file, the access mode, and the permissions. These permissions will be used if the file does not exist and O_CREATE
mode is specified. If the file already exists, the existing permissions are retained. Even when O_CREATE
mode is not used, as in this case, the function requires you to specify permissions.
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.OpenFile("test.txt", os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Println(err)
return
}
newLine := "File handling is easy."
_, err = fmt.Fprintln(f, newLine)
if err != nil {
fmt.Println(err)
f.Close()
return
}
err = f.Close()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("File appended successfully")
}
File appended successfully
cat test.txt
Already existent line
File handling is easy.
Concurrent writes:
Writing in parallel is as simple as calling the function responsible for writing using
go routines
; you just need to remember to use a waitGroup
to control when all of them have finished writing.
package main
import (
"fmt"
"os"
"strconv"
"sync"
)
func writeLine(f *os.File, newLine string, wg *sync.WaitGroup) {
_, err := fmt.Fprintln(f, newLine)
wg.Done()
if err != nil {
fmt.Println(err)
}
}
func main() {
f, err := os.OpenFile("test.txt", os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Println(err)
return
}
wg := sync.WaitGroup{}
for i := 1; i <= 300; i++ {
newLine := "Line: " + strconv.Itoa(i)
wg.Add(1)
go writeLine(f, newLine, &wg)
}
wg.Wait()
err = f.Close()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("File appended successfully")
}
File appended successfully
wc -l test.txt
300 test.txt