Question
I have many small files and do not want to read them line by line.
Is there a function in Go that reads an entire file into a string variable?
Short Answer
By the end of this page, you will understand how to read a complete file into memory in Go and convert it into a string. You will also learn when this approach is appropriate, how to handle errors safely, and what alternatives to use when files are too large to load all at once.
Concept
In Go, a file is usually read as a slice of bytes ([]byte) because files contain raw data. If the file contains text, you can convert those bytes into a string.
The most common beginner-friendly way to read an entire file is with the standard library function:
data, err := os.ReadFile("example.txt")
This returns the full file contents as []byte. You can then convert it to a string:
content := string(data)
This matters because many programs need the full contents of a file at once, such as:
- loading configuration files
- reading templates
- parsing JSON
- working with small text files
- processing test fixtures
Reading the whole file at once is simple and convenient, but it should mainly be used for small or reasonably sized files. For very large files, streaming or scanning line by line is usually better to avoid using too much memory.
Mental Model
Think of a file like a sealed envelope.
os.ReadFile()opens the envelope and pulls out everything at once.- The result is raw paper content as bytes (
[]byte). - Converting to
stringis like saying, "Treat these bytes as readable text."
This is convenient when the envelope is small. If the envelope is huge, dumping everything onto your desk at once can be messy and inefficient. In that case, reading piece by piece is better.
Syntax and Examples
Basic syntax
data, err := os.ReadFile("notes.txt")
if err != nil {
// handle error
}
content := string(data)
Complete example
package main
import (
"fmt"
"os"
)
func main() {
data, err := os.ReadFile("message.txt")
if err != nil {
fmt.Println("Error reading file:", err)
return
}
content := string(data)
fmt.Println(content)
}
What this does
os.ReadFile("message.txt")reads the whole file into memory.datais a[]byte.string(data)converts those bytes into a Go string.- If the file does not exist or cannot be opened,
errwill contain the problem.
If you only need bytes
If you are going to pass the contents to something that expects bytes, you may not need conversion at all:
Step by Step Execution
Consider this example:
package main
import (
"fmt"
"os"
)
func main() {
data, err := os.ReadFile("hello.txt")
if err != nil {
fmt.Println("Failed to read file:", err)
return
}
text := string(data)
fmt.Println(text)
}
Assume hello.txt contains:
Hello, Go!
Step by step
- The program starts in
main(). os.ReadFile("hello.txt")opens the file and reads all of its contents.- The contents are stored in
dataas bytes.- For example,
datamight represent the bytes forHello, Go!.
- For example,
- If something goes wrong,
erris notnil.- The program prints the error and stops early.
Real World Use Cases
Reading a whole file into a string is useful when the file is small and you need all of it at once.
Common uses
- Configuration files
- Read a JSON, YAML, or TOML file before parsing it.
- HTML or email templates
- Load a template file into memory for rendering.
- SQL scripts
- Read a
.sqlfile and execute its contents.
- Read a
- Test data
- Load fixture files for unit tests.
- Markdown or text content
- Read documentation, blog content, or prompts.
Example: reading a JSON file before parsing
data, err := os.ReadFile("config.json")
if err != nil {
return err
}
jsonText := string(data)
fmt.Println(jsonText)
In practice, you might skip converting to string if the parser accepts []byte.
Real Codebase Usage
In real Go projects, developers often read full files for convenience when the files are expected to be small.
Common patterns
Validate early
data, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("read %s: %w", path, err)
}
This is a common early return pattern for error handling.
Convert only when needed
content := string(data)
If a library accepts []byte, keep the bytes and avoid unnecessary conversion.
Wrap errors with context
data, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("could not load template file %q: %w", path, err)
}
This makes debugging easier in larger codebases.
Helper function pattern
func mustReadTextFile(path string) string {
data, err := os.ReadFile(path)
if err != nil {
(err)
}
(data)
}
Common Mistakes
1. Forgetting to handle the error
Broken code:
data, _ := os.ReadFile("missing.txt")
content := string(data)
fmt.Println(content)
Why it is a problem:
- If the file cannot be read, you silently ignore the failure.
- This makes bugs harder to find.
Better:
data, err := os.ReadFile("missing.txt")
if err != nil {
fmt.Println("Error:", err)
return
}
2. Assuming every file is text
Broken idea:
content := string(data)
This is only meaningful if the file actually contains text. Binary files like images or PDFs should usually stay as []byte.
3. Using this for very large files
Reading the whole file into memory can waste RAM.
Avoid this approach when:
- files are very large
- you only need part of the file
- you want to process line by line
4. Using outdated package names in new code
Older examples may use:
ioutil.ReadFile()
Comparisons
| Approach | Best for | Returns | Notes |
|---|---|---|---|
os.ReadFile | Small whole-file reads | []byte | Simplest way to read entire file |
bufio.Scanner | Reading line by line | tokens/lines | Good for text processing |
bufio.Reader | Streaming larger text input | chunks/strings | More flexible than Scanner |
os.Open + manual reads | Large or custom reading logic | bytes read into buffer | Useful for full control |
os.ReadFile vs line-by-line reading
Cheat Sheet
Quick reference
Read entire file
data, err := os.ReadFile("file.txt")
if err != nil {
return
}
Convert file bytes to string
content := string(data)
Full pattern
data, err := os.ReadFile(path)
if err != nil {
return err
}
text := string(data)
When to use it
- Small text files
- Config files
- Templates
- Test fixtures
When not to use it
- Very large files
- Streaming input
- Binary data you do not want as text
Important rules
os.ReadFilereturns[]byte, error- Always check
err - Convert to
stringonly if the file is text - Prefer
os.ReadFileover old in modern Go
FAQ
Is there a built-in Go function to read a whole file?
Yes. Use os.ReadFile() to read the entire file into memory.
How do I store the file contents in a string in Go?
Read the file as bytes, then convert it:
data, err := os.ReadFile("file.txt")
content := string(data)
Why does os.ReadFile return []byte instead of string?
Because files can contain any kind of data, not just text. Bytes are the most general representation.
Should I use os.ReadFile for large files?
Usually no. For large files, streaming with bufio.Scanner, bufio.Reader, or manual reads is often better.
What happened to ioutil.ReadFile?
It appears in older Go code, but modern Go code should use os.ReadFile.
Can I read JSON or YAML files this way?
Yes. This is very common for small config files. Some parsers accept []byte directly, so conversion to string may not be necessary.
What if the file does not exist?
Mini Project
Description
Build a small Go program that loads a text file and prints its contents along with the number of characters it contains. This demonstrates how to read a full file into memory, convert bytes to a string, and handle file errors properly.
Goal
Create a Go program that reads an entire text file into a string and prints both the content and its length.
Requirements
- Read a file from disk using the Go standard library.
- Handle the case where the file cannot be opened or read.
- Convert the file contents from
[]bytetostring. - Print the file contents.
- Print the number of characters in the resulting string.
Keep learning
Related questions
Blank Identifier Imports in Go: What `_` Means in an Import Statement
Learn what `_` means in a Go import, why blank identifier imports run package init code, and when to use them safely.
Check if a Value Exists in a Slice in Go
Learn how to check whether a value exists in a slice in Go, and why Go has no Python-style `in` operator for arrays or slices.
Concatenating Slices in Go with append
Learn how to concatenate two slices in Go using append and the ... operator, with examples, pitfalls, and practical usage.