Lab 08: I/O and Files

Time: 30 minutes | Level: Practitioner | Docker: docker run -it --rm golang:1.22-alpine sh

Overview

Go's I/O model is built around interfaces (io.Reader, io.Writer, io.Closer) that compose cleanly. The os, bufio, io, and embed packages cover everything from file operations to embedded assets.

Step 1: os.ReadFile / os.WriteFile

The simplest file operations — read/write entire files.

package main

import (
    "fmt"
    "os"
)

func main() {
    // Write
    content := []byte("Hello, Go!\nLine 2\nLine 3\n")
    err := os.WriteFile("/tmp/hello.txt", content, 0644)
    if err != nil {
        panic(err)
    }
    fmt.Println("written")

    // Read
    data, err := os.ReadFile("/tmp/hello.txt")
    if err != nil {
        panic(err)
    }
    fmt.Print(string(data))
}

💡 Tip: os.ReadFile reads the entire file into memory. For large files, use os.Open + streaming reads.

Step 2: os.Open / os.Create — Low-Level File Ops

Step 3: bufio.Scanner — Line-by-Line Reading

Step 4: bufio.Writer — Buffered Writing

💡 Tip: Always call Flush() before closing a bufio.Writer. Data in the buffer is lost otherwise.

Step 5: io.Reader / io.Writer / io.Copy

Step 6: filepath.Walk and filepath.WalkDir

Step 7: Temporary Files and Directories

Step 8: Capstone — Log Rotation Writer

📸 Verified Output:

Summary

API
Purpose
Notes

os.ReadFile / os.WriteFile

Read/write entire file

Simple; loads all into memory

os.Open / os.Create

Low-level file handles

Remember to Close() (use defer)

os.OpenFile

Open with mode flags

O_APPEND, O_RDWR, etc.

bufio.Scanner

Line/word/token scanning

Check scanner.Err() after loop

bufio.NewWriter

Buffered writes

Must call Flush()

io.Reader/Writer

Universal I/O interfaces

Compose via io.Copy, io.TeeReader

io.ReadAll

Read everything from Reader

Returns []byte

filepath.Walk / WalkDir

Recursive directory traversal

WalkDir is more efficient

os.CreateTemp

Temp file with unique name

Use defer os.Remove(f.Name())

Last updated