Golang os package: Open, Create, WriteFile, and *os.File

Golang os package for files: golang os open and OpenFile, os create golang with os.Create, os writefile golang with os.WriteFile, *os.File reads and append, Stat and errors.Is(os.ErrNotExist), Remove.

Published

Updated

Read time 4 min read

Reviewed byDeepak Prasad

Golang os package: Open, Create, WriteFile, and *os.File

The standard library os package is what people mean by searches like golang os or os golang: paths on disk, golang os open style reads, os create golang with os.Create, os writefile golang with os.WriteFile, and streaming I/O through *os.File. This article sticks to that golang file API; for more read patterns, see ways to read a file in Go.

Tested with Go 1.24 on Linux.


golang os package and *os.File

os exposes functions such as Open, Create, OpenFile, ReadFile, WriteFile, Stat, Remove, and Rename. Successful open or create calls return a concrete *os.File, which implements io.Reader, io.Writer, io.Closer, and related interfaces, so helpers that take those interfaces accept a *os.File after you open or create it.


golang os open (os.Open, os.OpenFile)

os.Open opens a path read-only and matches the usual os open golang flow when you only need to read bytes or scan lines. os.OpenFile is the general form: you pass flags such as os.O_RDONLY, os.O_WRONLY, os.O_RDWR, plus os.O_CREATE, os.O_APPEND, and os.O_TRUNC as needed, and a FileMode used when new files are created (subject to the process umask on Unix).

Always check the error before using the file, then defer Close on the non-nil *os.File:

go
package main

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

func main() {
	f, err := os.Open("notes.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	sc := bufio.NewScanner(f)
	for sc.Scan() {
		fmt.Println(sc.Text())
	}
	if err := sc.Err(); err != nil {
		log.Fatal(err)
	}
}

Run it from a directory that contains notes.txt; each line prints once. For whole small files, os.ReadFile avoids managing a Close yourself:

go
package main

import (
	"fmt"
	"log"
	"os"
)

func main() {
	b, err := os.ReadFile("notes.txt")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Print(string(b))
}

os create golang (os.Create)

os.Create creates or truncates the named file and opens it read-write. Typical os create golang code then writes through the returned *os.File. Do not defer Close until you know err is nil:

go
package main

import (
	"fmt"
	"log"
	"os"
)

func main() {
	f, err := os.Create("demo.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	if _, err := f.WriteString("hello\n"); err != nil {
		log.Fatal(err)
	}
	fmt.Println("created and wrote")
}
text
created and wrote

demo.txt then contains hello on its own line.


os writefile golang and appending (os.WriteFile, OpenFile)

os.WriteFile is the usual os writefile golang choice when you have a []byte (or a string converted to bytes) and want create-or-truncate behavior in one call:

go
package main

import (
	"log"
	"os"
)

func main() {
	if err := os.WriteFile("out.txt", []byte("first\n"), 0o644); err != nil {
		log.Fatal(err)
	}
}

To append without truncating, open with os.O_APPEND|os.O_CREATE|os.O_WRONLY:

go
package main

import (
	"log"
	"os"
)

func main() {
	f, err := os.OpenFile("out.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
	if err != nil {
		log.Fatal(err)
	}
	if _, err := f.WriteString("second\n"); err != nil {
		f.Close()
		log.Fatal(err)
	}
	if err := f.Close(); err != nil {
		log.Fatal(err)
	}
}

After both snippets, out.txt contains two lines (first then second). Pick 0o644 or tighter modes for real services; the effective mode still respects umask on Unix.


Stat, remove, and “file exists”

os.Stat returns fs.FileInfo (size, mod time, mode, directory bit). Combine it with errors.Is and os.ErrNotExist instead of parsing error strings; wording for golang file errors differs across operating systems. The snippet below assumes out.txt already exists from the os.WriteFile / append examples in the same working directory.

go
package main

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

func main() {
	if _, err := os.Stat("missing.txt"); err != nil {
		fmt.Println("missing:", errors.Is(err, os.ErrNotExist))
	}
	fi, err := os.Stat("out.txt")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("size=%d mod=%s\n", fi.Size(), fi.ModTime().UTC().Format(time.RFC3339))
}

os.Remove deletes a file; a missing path returns an error whose message depends on the platform:

text
remove gone.txt: no such file or directory

Summary

The golang os package centers on paths and *os.File handles. Golang os open style code uses os.Open for read-only work or os.OpenFile when you need create, append, or read-write combinations. The os create golang pattern maps to os.Create, which truncates existing paths. The os writefile golang pattern maps to os.WriteFile for small one-shot writes, while append and mixed modes stay on OpenFile. Check errors before defer Close, use errors.Is(err, os.ErrNotExist) after Stat, and choose ReadFile or a scanner depending on file size.


References


Frequently Asked Questions

1. What is the difference between os.Open and os.OpenFile in Go?

os.Open opens a path read-only (like OpenFile with O_RDONLY). os.OpenFile lets you pass flags such as O_RDWR, O_CREATE, O_APPEND, and TRUNC together with a permission bit mask when creating files.

2. When should I use os.WriteFile instead of os.Create?

os.WriteFile writes a full byte slice in one call, creating or truncating the file and setting permissions; it is ideal for small or generated blobs. os.Create truncates or creates then returns *os.File for incremental writes, Seek, or mixing Read and Write.

3. Where should I call Close on *os.File?

Call defer f.Close() only after a non-nil *os.File is returned and you have checked the error from Open, Create, or OpenFile; closing a nil file panics.

4. How do I check if a file exists in golang os code?

Use os.Stat(name) and errors.Is(err, os.ErrNotExist) for existence; avoid fragile string comparisons on the error message because text differs by OS and locale.
Tuan Nguyen

Data Scientist

Proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise …