Web Analytics

File I/O

Intermediate ~30 min read

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

Output
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

Output
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!