← Back to Go Course | Chapter 13: File IO & OS | Lesson 2 of 7

Reading Files

Reading a file in Go is like opening a book someone else wrote and copying its words into your own notes so your program can use them.

Reading an Entire File with os.ReadFile

os.ReadFile opens, reads, and closes a file in one call, returning its full contents as a byte slice -- the simplest option when a file is small enough to comfortably fit in memory.

Example: Reading an Entire File with os.ReadFile

markup
package main

import (
	"fmt"
	"io/ioutil"
)

func main() {
	ioutil.WriteFile("greeting.txt", []byte("Hello from Go!"), 0644)
	data, err := ioutil.ReadFile("greeting.txt")
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Println(string(data))
}

Opening and Closing a File Explicitly

os.Open gives lower-level control, returning a *os.File you can read from incrementally -- it must be explicitly closed with Close() once you're done, conventionally deferred immediately after opening succeeds.

Note: Always defer file.Close() right after a successful os.Open, to guarantee the file is released.

Example: Opening and Closing a File Explicitly

markup
package main

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

func main() {
	ioutil.WriteFile("notes.txt", []byte("line one"), 0644)
	f, err := os.Open("notes.txt")
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	defer f.Close()

	buf := make([]byte, 8)
	n, _ := f.Read(buf)
	fmt.Println(string(buf[:n]))
}

Checking If a File Exists

os.Stat returns file metadata, and checking its error with os.IsNotExist lets you distinguish 'file doesn't exist' from other kinds of errors, like a permissions problem.

Example: Checking If a File Exists

markup
package main

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

func main() {
	ioutil.WriteFile("exists.txt", []byte("data"), 0644)
	_, err := os.Stat("exists.txt")
	fmt.Println("exists.txt exists:", !os.IsNotExist(err))

	_, err = os.Stat("missing.txt")
	fmt.Println("missing.txt exists:", !os.IsNotExist(err))
}
Common Mistakes
  1. Forgetting to close an opened file with defer file.Close(), which can leak file descriptors in long-running programs.
  2. Using os.ReadFile on a huge file when a buffered, streaming read would be far more memory-efficient.
  3. Not checking the error from os.ReadFile/os.Open, silently proceeding with empty or partial data if the file is missing.
Chapter Summary
  • os.ReadFile reads an entire file into memory in one call, returning its bytes and an error.
  • os.Open gives more control for reading a file incrementally, and must be paired with defer file.Close().
  • File paths in Judge0's sandbox aren't guaranteed to exist, so runnable examples should create their own temp file first.
  • Always check the error returned by file operations before trusting the result.
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.