Mastering Formatted and File I/O in Go

Arya M. PathakArya M. Pathak
4 min read

In this blog, we'll delve into the world of formatted and file I/O in Go. We'll explore the powerful fmt package for formatted I/O and the os and io packages for file operations. Along the way, we'll demonstrate these concepts with plenty of code examples to illustrate how they work and why they're useful.

Standard I/O Streams in Go

Go, like many modern programming languages, provides access to standard I/O streams: standard input, standard output, and standard error. These are exposed via the os package as os.Stdin, os.Stdout, and os.Stderr. Let's start by understanding the basic usage of these streams.

Printing to Standard Output

The fmt package provides several functions for printing to the console. The most basic is fmt.Println, which prints its arguments followed by a newline. For more control over formatting, we use fmt.Printf.

package main

import (
    "fmt"
    "os"
)

func main() {
    fmt.Println("This is printed to standard output.")

    // Using Printf for formatted output
    name := "Alice"
    age := 30
    fmt.Printf("Name: %s, Age: %d\n", name, age)

    // Redirecting output to standard error
    fmt.Fprintf(os.Stderr, "This is an error message.\n")
}

Formatting Strings with fmt

The fmt package includes functions like fmt.Sprintf, which returns a formatted string instead of printing it. This is useful when you need to store the formatted string for later use.

func main() {
    name := "Alice"
    age := 30
    formattedString := fmt.Sprintf("Name: %s, Age: %d", name, age)
    fmt.Println(formattedString)
}

Formatting Verbs in Go

Formatting verbs in Go are placeholders within a format string. Here are some common verbs:

  • %s: String

  • %d: Decimal integer

  • %x: Hexadecimal integer

  • %f: Floating point

  • %t: Boolean

  • %v: Default format

func main() {
    // Formatting integers
    number := 255
    fmt.Printf("Decimal: %d, Hex: %x, Binary: %b\n", number, number, number)

    // Formatting floating-point numbers
    pi := 3.14159
    fmt.Printf("Default float: %f, Two decimals: %.2f\n", pi, pi)

    // Formatting booleans and generic values
    isTrue := true
    fmt.Printf("Boolean: %t, Generic: %v\n", isTrue, isTrue)
}

File I/O in Go

File I/O in Go is straightforward with the os package. Let's start with reading files.

Reading Files

To read a file, we use os.Open to get a file handle and bufio.NewScanner to read it line by line.

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    file, err := os.Open("example.txt")
    if err != nil {
        fmt.Fprintf(os.Stderr, "Error opening file: %v\n", err)
        return
    }
    defer file.Close()

    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }

    if err := scanner.Err(); err != nil {
        fmt.Fprintf(os.Stderr, "Error reading file: %v\n", err)
    }
}

Writing Files

To write to a file, we use os.Create to create or truncate the file, and fmt.Fprintf to write to it.

func main() {
    file, err := os.Create("output.txt")
    if err != nil {
        fmt.Fprintf(os.Stderr, "Error creating file: %v\n", err)
        return
    }
    defer file.Close()

    fmt.Fprintf(file, "This is a line of text.\n")
    fmt.Fprintf(file, "This is another line of text.\n")
}

Using io/ioutil for Simple File Operations

The io/ioutil package provides convenient functions for simple file operations, like reading an entire file into memory.

package main

import (
    "fmt"
    "io/ioutil"
    "os"
)

func main() {
    data, err := ioutil.ReadFile("example.txt")
    if err != nil {
        fmt.Fprintf(os.Stderr, "Error reading file: %v\n", err)
        return
    }
    fmt.Println(string(data))

    err = ioutil.WriteFile("output.txt", data, 0644)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Error writing file: %v\n", err)
    }
}

Building a Simple cat Program

Let's combine these concepts to build a simple version of the Unix cat command, which reads files and prints their contents to standard output.

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    if len(os.Args) < 2 {
        fmt.Fprintf(os.Stderr, "Usage: %s <file1> <file2> ...\n", os.Args[0])
        os.Exit(1)
    }

    for _, filename := range os.Args[1:] {
        file, err := os.Open(filename)
        if err != nil {
            fmt.Fprintf(os.Stderr, "Error opening file %s: %v\n", filename, err)
            continue
        }

        if _, err := io.Copy(os.Stdout, file); err != nil {
            fmt.Fprintf(os.Stderr, "Error reading file %s: %v\n", filename, err)
        }

        file.Close()
    }
}

Building a Word Count Program

We'll now create a program that mimics the Unix wc command, counting lines, words, and characters in a file.

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func main() {
    if len(os.Args) < 2 {
        fmt.Fprintf(os.Stderr, "Usage: %s <file1> <file2> ...\n", os.Args[0])
        os.Exit(1)
    }

    for _, filename := range os.Args[1:] {
        file, err := os.Open(filename)
        if err != nil {
            fmt.Fprintf(os.Stderr, "Error opening file %s: %v\n", filename, err)
            continue
        }

        lines, words, chars := 0, 0, 0
        scanner := bufio.NewScanner(file)
        for scanner.Scan() {
            lines++
            text := scanner.Text()
            words += len(strings.Fields(text))
            chars += len(text)
        }

        if err := scanner.Err(); err != nil {
            fmt.Fprintf(os.Stderr, "Error reading file %s: %v\n", filename, err)
        }

        fmt.Printf("%d %d %d %s\n", lines, words, chars, filename)
        file.Close()
    }
}

In this post, we've covered the basics of formatted and file I/O in Go. We explored the fmt package for printing and formatting strings and the os and io packages for file operations. We also built simple versions of the Unix cat and wc commands to demonstrate these concepts in action. With these tools, you can handle a wide range of I/O tasks in your Go programs.

10
Subscribe to my newsletter

Read articles from Arya M. Pathak directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Arya M. Pathak
Arya M. Pathak

Backend Dev | VIT Pune '26 | 🐈Cat Connoisseur /⁠ᐠ⁠。⁠ꞈ⁠。⁠ᐟ⁠\