File I/O
File I/O is essential for reading configuration, processing data, and saving results. Go provides powerful packages for file operations. In this lesson, you'll master reading, writing, and managing files.
Reading Files
1. Read Entire File
Click Run to execute your code
2. Read Line by Line
func readLines(filename string) ([]string, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
}
3. Read with Buffer
func readWithBuffer(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
reader := bufio.NewReader(file)
buffer := make([]byte, 1024)
for {
n, err := reader.Read(buffer)
if err == io.EOF {
break
}
if err != nil {
return err
}
fmt.Print(string(buffer[:n]))
}
return nil
}
Writing Files
1. Write Entire File
Click Run to execute your code
2. Append to File
func appendToFile(filename, text string) error {
file, err := os.OpenFile(filename,
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer file.Close()
_, err = file.WriteString(text + "\n")
return err
}
3. Buffered Writing
func writeWithBuffer(filename string, lines []string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
writer := bufio.NewWriter(file)
for _, line := range lines {
_, err := writer.WriteString(line + "\n")
if err != nil {
return err
}
}
return writer.Flush() // Important!
}
File Operations
Check if File Exists
func fileExists(filename string) bool {
_, err := os.Stat(filename)
return !os.IsNotExist(err)
}
// Or more detailed
func checkFile(filename string) {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
fmt.Println("File does not exist")
return
}
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Name:", info.Name())
fmt.Println("Size:", info.Size(), "bytes")
fmt.Println("Mode:", info.Mode())
fmt.Println("Modified:", info.ModTime())
fmt.Println("IsDir:", info.IsDir())
}
Copy, Move, Delete
// Copy file
func copyFile(src, dst string) error {
data, err := os.ReadFile(src)
if err != nil {
return err
}
return os.WriteFile(dst, data, 0644)
}
// Move/Rename file
func moveFile(oldPath, newPath string) error {
return os.Rename(oldPath, newPath)
}
// Delete file
func deleteFile(filename string) error {
return os.Remove(filename)
}
Working with Directories
// Create directory
os.Mkdir("mydir", 0755)
os.MkdirAll("path/to/mydir", 0755) // Create all parent dirs
// List directory
entries, err := os.ReadDir(".")
if err != nil {
log.Fatal(err)
}
for _, entry := range entries {
fmt.Println(entry.Name(), entry.IsDir())
}
// Walk directory tree
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
fmt.Println(path, info.Size())
return nil
})
// Remove directory
os.Remove("mydir") // Empty dir only
os.RemoveAll("mydir") // Recursive
File Permissions
| Mode | Octal | Description |
|---|---|---|
| 0644 | rw-r--r-- | Owner: read/write, Others: read |
| 0755 | rwxr-xr-x | Owner: all, Others: read/execute |
| 0600 | rw------- | Owner: read/write only |
| 0777 | rwxrwxrwx | Everyone: all permissions |
Common Mistakes
1. Forgetting to close files
// β Wrong - file not closed
file, _ := os.Open("file.txt")
// ... use file ...
// β
Correct - use defer
file, err := os.Open("file.txt")
if err != nil {
return err
}
defer file.Close() // Always close!
2. Not checking errors
// β Wrong - ignoring errors
data, _ := os.ReadFile("config.json")
// β
Correct - handle errors
data, err := os.ReadFile("config.json")
if err != nil {
log.Fatal(err)
}
3. Not flushing buffers
// β Wrong - data might not be written
writer := bufio.NewWriter(file)
writer.WriteString("data")
// Missing flush!
// β
Correct - flush before closing
writer := bufio.NewWriter(file)
writer.WriteString("data")
writer.Flush() // Ensure data is written
Exercise: Log File Manager
Task: Create a log file manager.
Requirements:
- Create a function to append log entries with timestamps
- Read and display all log entries
- Clear old logs (delete file)
- Handle errors properly
Show Solution
package main
import (
"bufio"
"fmt"
"os"
"time"
)
const logFile = "app.log"
func appendLog(message string) error {
file, err := os.OpenFile(logFile,
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer file.Close()
timestamp := time.Now().Format("2006-01-02 15:04:05")
logEntry := fmt.Sprintf("[%s] %s\n", timestamp, message)
_, err = file.WriteString(logEntry)
return err
}
func readLogs() error {
file, err := os.Open(logFile)
if err != nil {
if os.IsNotExist(err) {
fmt.Println("No logs found")
return nil
}
return err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
return scanner.Err()
}
func clearLogs() error {
return os.Remove(logFile)
}
func main() {
// Write logs
appendLog("Application started")
appendLog("Processing data")
appendLog("Task completed")
// Read logs
fmt.Println("=== Log Entries ===")
if err := readLogs(); err != nil {
fmt.Println("Error reading logs:", err)
}
// Clear logs
fmt.Println("\nClearing logs...")
if err := clearLogs(); err != nil {
fmt.Println("Error clearing logs:", err)
} else {
fmt.Println("Logs cleared successfully")
}
}
Summary
- os.ReadFile() reads entire file
- os.WriteFile() writes entire file
- bufio for buffered I/O (efficient)
- defer file.Close() always close files
- os.Stat() gets file info
- filepath.Walk() traverses directories
- Always check errors for file operations
What's Next?
Now that you can work with files, you're ready to learn about JSON & HTTP. You'll discover how to work with JSON data and make HTTP requestsβessential for modern applications!
Enjoying these tutorials?