Skip to content
Select theme

How to read a file into a String

Short answer: std::fs::read_to_string(path) reads a whole file and hands back an io::Result<String>. It assumes the file is UTF-8 — bytes that aren’t valid UTF-8 come back as an Err with kind InvalidData, never as garbled text.

From a fresh project — cargo new read-demo, then replace the contents of src/main.rs with each block below and run it with cargo run. The project name shows up only in cargo’s own output; nothing else on this page depends on it. Each block writes the file it reads before reading it, so it runs on its own; in your own code the file is already there and you delete that line.

Leaves are falling
softly on the path
38 bytes

One call opens the file, reads it to the end and gives you a String — no buffer to size, no loop to write. The ? on each line is what turns a failure into an early return: main’s return type is io::Result<()>, so an error prints the message and exits with status 1 instead of panicking. The path is relative to the directory you run the program from, which under cargo run is the project root — that’s where poem.txt lands.

A missing file is an error like any other, and it’s the one every reader hits first:

No such file or directory (os error 2)
Os { code: 2, kind: NotFound, message: "No such file or directory" }
NotFound: true

The two print lines are the same error in two forms: {err} is the human-readable Display, and {err:?} is the Debug, which also names the ErrorKind. Match on err.kind() when a missing file is an acceptable outcome — a config file that doesn’t exist yet is not a crash — and propagate everything else with ?.

read_to_string returns a String, and a String can only hold valid UTF-8. So the function reads the bytes and then checks them, and a file in another encoding fails:

Error { kind: InvalidData, message: "stream did not contain valid UTF-8" }

The file was read fine; the error is about the bytes, not the disk, which is why the kind is InvalidData rather than something from the OS. This is the guarantee doing its job: no String in Rust can hold text that isn’t UTF-8, so the conversion that would produce one fails instead. When the file isn’t text at all — an image, an archive, a payload in a fixed-width encoding — fs::read gives you a Vec<u8> and leaves the decoding to you. That has its own article later in this chapter, as does reading the file line by line.