Apps Artificial Intelligence CSS DevOps Go JavaScript Laravel Linux MongoDB MySQL PHP Python Rust Svelte Vue

How to Check Whether a File Exists in Go

2 min read .
How to Check Whether a File Exists in Go

Checking whether a file exists is a common task when working with configuration, local state, generated output, or other filesystem resources. Go’s os package provides the necessary APIs, but it is important to distinguish “does not exist” from other errors such as permission failures.

1. Check with os.Stat

os.Stat returns file metadata when the path can be resolved:

package main

import (
	"errors"
	"fmt"
	"os"
)

func fileExists(filename string) (bool, error) {
	_, err := os.Stat(filename)
	if err == nil {
		return true, nil
	}
	if errors.Is(err, os.ErrNotExist) {
		return false, nil
	}
	return false, err
}

func main() {
	filename := "example.txt"

	exists, err := fileExists(filename)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	if exists {
		fmt.Printf("File '%s' exists.\n", filename)
	} else {
		fmt.Printf("File '%s' does not exist.\n", filename)
	}
}

Returning an error prevents permission or I/O problems from being mistaken for a missing file.

2. Distinguish Files from Directories

If the path must specifically refer to a regular file:

func fileExists(filename string) (bool, error) {
	info, err := os.Stat(filename)
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {
			return false, nil
		}
		return false, err
	}

	if info.IsDir() {
		return false, fmt.Errorf("'%s' is a directory, not a file", filename)
	}

	return true, nil
}

Depending on your requirements, you may also want to check info.Mode().IsRegular() rather than merely rejecting directories.

3. Open the File Directly When You Need to Read It

If the next operation is to open the file anyway, avoid a separate existence check. Checking first creates a race: the file can disappear or change between Stat and Open.

file, err := os.Open("example.txt")
if err != nil {
	if errors.Is(err, os.ErrNotExist) {
		fmt.Println("File does not exist")
		return
	}

	fmt.Println("Open error:", err)
	return
}
defer file.Close()

// Read from file here.

This “attempt the operation and handle the error” pattern is often the safest approach.

Best Practices

  • Use os.Stat when you truly need metadata or an existence check before presenting information to a user.
  • Open the file directly if you intend to read it immediately afterward.
  • Use errors.Is(err, os.ErrNotExist) or os.IsNotExist(err) for missing-path errors.
  • Do not treat every error as “file missing”; permission and filesystem errors need different handling.
  • Remember that existence checks cannot guarantee the file will still exist by the time you use it.

Conclusion

Go makes filesystem checks straightforward, but robust code should preserve the distinction between a missing path and an operational error. Use os.Stat for metadata and direct os.Open calls when access is the real goal.

Related Posts

chevron-up