In the previous post, we have introduced some examples of working with files in Golang. In today's post, we will walk through how to read and update same file.
Different methods to read and update file in GO
Update file using os.OpenFile
with os.O_APPEND
flag and Write() function
func OpenFile(name string, flag int, perm FileMode) (*File, error)
: OpenFile is the generalized open call; most users will use Open or Create instead. It opens the named file with specified flag (O_RDONLY etc.). If the file does not exist, and the O_CREATE flag is passed, it is created with mode perm (before umask). If successful, methods on the returned File can be used for I/O. If there is an error, it will be of type *PathError.
Here is an example of reading and appending some text at the end of file:
package main
import (
"log"
"os"
"fmt"
"bufio"
)
func main() {
// Append to the file
file, err := os.OpenFile("test.log", os.O_APPEND, 0660)
if err != nil {
log.Fatal(err)
}
// print out the content of file before modify
fmt.Println("Before modified: ")
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
appendContent := `
This is the append line`
if _, err := file.Write([]byte(appendContent)); err != nil {
file.Close()
log.Fatal(err)
}
if err := file.Close(); err != nil {
log.Fatal(err)
}
}
Output:
Before modified:
This is log file
And the test.log
after modified:
This is log file
This is the append line
Using WriteString() function to append string to a file
The example below show how to use WriteString() function to append string to a file:
package main
import (
"fmt"
"os"
)
func main() {
fileData := []byte("This is example of writing line to a file\n")
// if the WriteFile method failed then returns an error
err := os.WriteFile("./fileData.txt", fileData, 0666)
// handle this error
if err != nil {
fmt.Println(err)
}
content, err := os.ReadFile("./fileData.txt")
if err != nil {
fmt.Println(err)
}
fmt.Print(string(content[:]))
file, err := os.OpenFile("./fileData.txt", os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
panic(err)
}
defer file.Close()
if _, err = file.WriteString("new line has been appended\n"); err != nil {
panic(err)
}
content, err = os.ReadFile("./fileData.txt")
if err != nil {
fmt.Println(err)
}
fmt.Println("After append:")
fmt.Print(string(content[:]))
}
Output:
This is example of writing line to a file
After append:
This is example of writing line to a file
new line has been appended
Using WriteAt() function to update a file in Golang
Using the WriteAt()
function, which writes len(b) bytes to the File beginning at byte offset off. The amount of bytes written and any errors are returned.
func (f *File) WriteAt(b []byte, off int64) (n int, err error)
: WriteAt writes len(b) bytes to the File starting at byte offset off. It returns the number of bytes written and an error, if any. WriteAt
returns a non-nil error when n != len(b)
. If file was opened with the O_APPEND flag, WriteAt
returns an error.
The first word of a text file is modified in the example below:
package main
import (
"log"
"fmt"
"os"
)
func Modify() {
// OpenFile with Read Write Mode
file, err := os.OpenFile("test.txt", os.O_RDWR, 0644)
if err != nil {
log.Fatalf("open file failed: %s", err)
}
defer file.Close()
lenUpdate, err := file.WriteAt([]byte("These"), 0) // Write at 0 beginning
if err != nil {
log.Fatalf("write to file failed: %s", err)
}
fmt.Printf("Length update: %d bytes\n", lenUpdate)
fmt.Printf("File Name: %s\n", file.Name())
}
func ReadFile() {
data, err := os.ReadFile("test.txt")
if err != nil {
log.Panicf("read data from file failed: %s", err)
}
fmt.Printf("File Content: %s\n", string(data[:]))
}
func main() {
fmt.Println("Read file before modify")
ReadFile()
fmt.Println("Using WriteAt function")
Modify()
fmt.Println("Read file after modify")
ReadFile()
}
Output:
Read file before modify
File Content: Gello GoLinuxCloud member!
Using WriteAt function
Length update: 5 bytes
File Name: test.txt
Read file after modify
File Content: These GoLinuxCloud member!
Buffered read write same file in go
The answer is to double-open the file, once for reading and once for overwriting the data. In the below example, we read every line using a loop and replace "Midas" by "GoLinuxCloud"
package main
import (
"fmt"
"os"
"log"
"bufio"
"strings"
"io"
)
func main() {
outFile, _ := os.OpenFile("file.txt", os.O_RDWR, 0777)
defer outFile.Close()
file, err := os.OpenFile("file.txt", os.O_RDWR, 0777)
if err != nil {
log.Fatal(err)
}
reader := bufio.NewReaderSize(file, 10*1024)
for {
line, err := reader.ReadString('\n')
line = strings.Replace(line, "Midas", "GoLinuxCloud", -1)
outFile.WriteString(line)
if err != nil {
if err != io.EOF {
fmt.Println("error:", err)
}
break
}
}
}
Output:
There once was a king named GoLinuxCloud who did a good deed for a Satyr. And he was then granted a wish by Dionysus, the god of wine.
For his wish, GoLinuxCloud asked that whatever he touched would turn to gold. Despite Dionysus’ efforts to prevent it, GoLinuxCloud pleaded that this was a fantastic wish, and so, it was bestowed.
Excited about his newly-earned powers, GoLinuxCloud started touching all kinds of things, turning each item into pure gold.
But soon, GoLinuxCloud became hungry. As he picked up a piece of food, he found he couldn’t eat it. It had turned to gold in his hand.
Hungry, GoLinuxCloud groaned, “I’ll starve! Perhaps this was not such an excellent wish after all!”
Seeing his dismay, GoLinuxCloud’ beloved daughter threw her arms around him to comfort him, and she, too, turned to gold. “The golden touch is no blessing,” GoLinuxCloud cried
Summary
In this tutorial, we have shown some example of reading updating same file in Golang. We have multiple functions such as: Write()
, WriteString()
, WriteAt()
,... to do this task. It’s incredibly important to understand the various different file permissions available to you when you are writing to new files.
References
https://pkg.go.dev/os#FileMode
https://pkg.go.dev/bufio#NewReaderSize