Go File Handle
File handling is one of the most common operations in Goβreading configurations, writing logs, and data persistence allcannot do without it. Go's standard library provides a concise yet powerful set of file I/O interfaces, covering scenarios from single read/write operations to streaming processing.
There are 5 core packages related to file handling, each with its own responsibilities:
> **Version Note:** The `ioutil` package was deprecated in Go 1.16, and its functionality has been migrated to `os` (such as `os.ReadFile`, `os.WriteFile`) and `io` (such as `io.ReadAll`). New code should directly use the `os` and `io` packages.
* * *
## 1. File Creation
`os.Create` creates a new file. If the file already exists, it will be truncated (content cleared). The returned file object must be closed to release system resources:
## Example
package main
import(
"log"
"os"
)
func main(){
// os.Create creates a file (existing file will be cleared)
file, err := os.Create("test.txt")
if err !=nil{
log.Fatal(err)
}
defer file.Close()// defer ensures file is closed when function ends
// Write content to verify creation succeeded
file.WriteString("File created successfullyn")
log.Println("File created successfully")
}
> **`defer file.Close()`** is the best practice for Go file operations. `defer` ensures that even if subsequent code panics, the file will be properly closed, avoiding file descriptor leaks.
* * *
## 2. File Opening and Closing
The `os` package provides three ways to open files, suitable for different scenarios:
| Function | Mode | Description |
| --- | --- | --- |
| `os.Open(name)` | Read-only | Simplest way, opens for reading only |
| `os.Create(name)` | Read/Write + Create/Truncate | Creates new file or clears existing file |
| `os.OpenFile(name, flag, perm)` | Custom | Can specify read/write, append, create and other flags |
## Example
package main
import(
"fmt"
"os"
)
func main(){
// Method 1: Open for reading only
file, err := os.Open("example.txt")
if err !=nil{
fmt.Println("Failed to open:", err)
return
}
defer file.Close()
fmt.Println("File opened successfully")
// Method 2: OpenFile with custom mode
// os.O_WRONLY write-only
// os.O_CREATE create if not exists
// os.O_APPEND append mode
// os.O_TRUNC truncate if exists
f, err := os.OpenFile("log.txt",
os.O_WRONLY|os.O_CREATE|os.O_APPEND,0644)
if err !=nil{
fmt.Println("Failed to open:", err)
return
}
defer f.Close()
f.WriteString("Append a log linen")
}
### OpenFile Flag Description
| Flag | Description |
| --- | --- |
| `os.O_RDONLY` | Read-only (default) |
| `os.O_WRONLY` | Write-only |
| `os.O_RDWR` | Read-write |
| `os.O_APPEND` | Append mode, appends content to end of file |
| `os.O_CREATE` | Create file if it doesn't exist |
| `os.O_TRUNC` | Clear file content when opening |
| `os.O_EXCL` | Used with CREATE, returns error if file already exists |
* * *
## 3. File Reading
Go provides three main ways to read files, choose based on file size and processing requirements:
### 3.1 Read Entire File at Once (Recommended for Small Files)
`os.ReadFile` is the simplest wayβautomatically opens, reads, and closes the file in one step:
## Example
package main
import(
"fmt"
"log"
"os"
)
func main(){
// Read entire file at once (Go 1.16+)
data, err := os.ReadFile("config.json")
if err !=nil{
log.Fatal(err)
}
fmt.Println(string(data))
}
### 3.2 Read Line by Line (Recommended for Large Files)
For large files, use `bufio.Scanner` to process line by line, avoiding loading everything into memory at once:
## Example
package main
import(
"bufio"
"fmt"
"log"
"os"
)
func main(){
file, err := os.Open("large-file.log")
if err !=nil{
log.Fatal(err)
}
defer file.Close()
// Scan line by line
scanner := bufio.NewScanner(file)
lineNum :=0
for scanner.Scan(){
lineNum++
line := scanner.Text()// Get current line content
fmt.Printf("Line %d: %sn", lineNum, line)
}
// Check for errors during scanning
if err := scanner.Err(); err !=nil{
log.Fatal("Read error:", err)
}
}
> **Note:** `bufio.Scanner` has a default maximum line length of 64KB. If your file has lines longer than that, you need to call `scanner.Buffer(make([]byte, 0), maxSize)` before calling `Scan()` to increase the buffer size.
### 3.3 Using io.ReadAll to Read
When you already have an open `io.Reader` (such as a network response or an opened file), you can use `io.ReadAll`:
## Example
package main
import(
"fmt"
"io"
"log"
"os"
)
func main(){
file, err := os.Open("example.txt")
if err !=nil{
log.Fatal(err)
}
defer file.Close()
// Read all data from Reader
data, err := io.ReadAll(file)
if err !=nil{
log.Fatal(err)
}
fmt.Println(string(data))
}
* * *
## 4. File Writing
Go provides multiple writing methods, from simple one-time writes to high-performance buffered writes:
### 4.1 One-Time Write
`os.WriteFile` writes data to a file in one go (overwrites existing content):
## Example
package main
import(
"log"
"os"
)
func main(){
content :=[]byte("Hello, Go!n This is the second linen")
// 0644: owner read/write, others read-only
err := os.WriteFile("output.txt", content,0644)
if err !=nil{
log.Fatal(err)
}
log.Println("Write successful")
}
### 4.2 Using File Object to Write
Through the file object, you can write content in multiple steps:
## Example
package main
import(
"fmt"
"log"
"os"
)
func main(){
file, err := os.Create("output.txt")
if err !=nil{
log.Fatal(err)
}
defer file.Close()
// Method 1: Write string
file.WriteString("Write string directlyn")
// Method 2: Write byte slice
data :=[]byte("Write byte slicen")
file.Write(data)
// Method 3: Formatted write
fmt.Fprintf(file,"Formatted write: %d + %d = %dn",3,4,7)
}
### 4.3 Buffered Write (Recommended for Large Amounts of Data)
`bufio.Writer` first writes data to a memory buffer, then batch writes to disk when the buffer is full, significantly reducing I/O operations. Be sure to call `Flush()` before finishing:
## Example
package main
import(
"bufio"
"log"
"os"
)
func main(){
file, err := os.Create("buffered-output.txt")
if err !=nil{
log.Fatal(err)
}
defer file.Close()
// Create buffered writer
writer := bufio.NewWriter(file)
// Write multiple lines (go to buffer first, not immediately to disk)
for i:=0;i<1000;i++{
writer.WriteString("This is line "+ itoa(i)+"n")
}
// Flush writes remaining buffer data to file
if err := writer.Flush(); err !=nil{
log.Fatal("Failed to flush buffer:", err)
}
log.Println("Buffered write completed")
}
// Simple int to string helper function
func itoa(n int)string{
return fmt.Sprintf("%d", n)
}
* * *
## 5. File Append Writing
Use the `os.O_APPEND` flag to append content at the end of the file without overwriting existing data:
## Example
package main
import(
"log"
"os"
"time"
)
func main(){
// O_APPEND: append mode
// O_CREATE: create if not exists
// O_WRONLY: write-only
file,
YouTip