Comprehensive Guide to File Reading and Writing in Go: From Basics to Advanced Practices

Nov 20, 2025 · Programming · 11 views · 7.8

Keywords: Go programming | file operations | bufio | error handling | performance optimization

Abstract: This article provides an in-depth exploration of various file reading and writing methods in Go, covering basic file operations, buffered I/O with bufio, convenient one-shot operations, and error handling mechanisms. Through detailed code examples and principle analysis, developers can master core concepts and practical techniques for file operations in Go, including file opening, reading, writing, closing, and performance optimization recommendations.

Introduction

File operations are fundamental in any programming language, and Go provides multiple file reading and writing approaches through its concise yet powerful standard library. Based on Go 1.x versions, this article systematically introduces core methods for file operations, helping developers understand best practices for different scenarios.

Basic File Operations

Go uses the os package for basic file operations. os.Open is used to open existing files, while os.Create creates new files. Both functions are convenient wrappers around os.OpenFile, and in most cases, there's no need to call the underlying function directly.

The following example demonstrates file copying using basic methods:

package main

import (
    "io"
    "os"
)

func main() {
    // Open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()

    // Create output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()

    // Create buffer for reading data chunks
    buf := make([]byte, 1024)
    for {
        n, err := fi.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        if _, err := fo.Write(buf[:n]); err != nil {
            panic(err)
        }
    }
}

Key points analysis:

Buffered Reading and Writing with bufio

The bufio package provides buffered I/O capabilities that significantly improve performance for frequent small data reads and writes. It wraps basic file operations and offers a more user-friendly API.

package main

import (
    "bufio"
    "io"
    "os"
)

func main() {
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()

    r := bufio.NewReader(fi)

    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()

    w := bufio.NewWriter(fo)

    buf := make([]byte, 1024)
    for {
        n, err := r.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        if _, err := w.Write(buf[:n]); err != nil {
            panic(err)
        }
    }

    if err = w.Flush(); err != nil {
        panic(err)
    }
}

Advantages of bufio:

Convenient File Operations

For small files, convenient one-shot read/write methods can be used. Note that since Go 1.16, the ioutil package has been deprecated, with related functions migrated to os and io packages.

Modern Go versions recommend using:

package main

import "os"

func main() {
    // Read entire file
    data, err := os.ReadFile("input.txt")
    if err != nil {
        panic(err)
    }

    // Write entire file
    err = os.WriteFile("output.txt", data, 0644)
    if err != nil {
        panic(err)
    }
}

File permission explanations:

Best Practices for Error Handling

Go emphasizes explicit error handling. Common errors in file operations include:

Recommended structured error handling:

func copyFile(src, dst string) error {
    input, err := os.Open(src)
    if err != nil {
        return fmt.Errorf("failed to open source file: %w", err)
    }
    defer input.Close()

    output, err := os.Create(dst)
    if err != nil {
        return fmt.Errorf("failed to create destination file: %w", err)
    }
    defer output.Close()

    _, err = io.Copy(output, input)
    if err != nil {
        return fmt.Errorf("failed to copy file content: %w", err)
    }

    return output.Close()
}

Performance Optimization Recommendations

Choose appropriate read/write strategies based on file size and access patterns:

Conclusion

Go provides multi-level file operation APIs, from basic byte-level operations to advanced buffered reading and writing, capable of meeting requirements across different scenarios. Understanding the applicable scenarios and performance characteristics of these methods helps in writing efficient and reliable file processing code. In practical development, choose the most suitable file operation method based on specific requirements and always follow good error handling practices.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.