Standard I/O (stdio) operations are fundamental for any program that interacts with users or other processes. Rust provides safe, efficient access to standard input, output, and error streams through the std::io module.
Every process has three standard streams:
Use std::io::stdin() to get a handle to standard input:
use std::io::{self, BufRead};
let stdin = io::stdin();
let mut line = String::new();
stdin.read_line(&mut line)?;
// line now contains the input including newlineFor reading multiple lines, use the lines() iterator from BufRead:
use std::io::{self, BufRead};
let stdin = io::stdin();
for line in stdin.lock().lines() {
let line = line?;
println!("Read: {}", line);
}Use std::io::stdout() and std::io::stderr() for output handles:
use std::io::{self, Write};
let mut stdout = io::stdout();
writeln!(stdout, "Normal output")?;
stdout.flush()?; // Ensure output is written immediately
let mut stderr = io::stderr();
writeln!(stderr, "Error message")?;stdout is line-buffered when connected to a terminal, meaning output is flushed after each newline. When writing to a file or pipe, it's fully buffered. Use .flush() to ensure output is written immediately:
use std::io::{self, Write};
print!("Enter your name: ");
// Important! Without this, prompt might not appear
io::stdout().flush()?;Implement the following functions for working with standard I/O:
read_line_from_reader<R: BufRead>(reader: R) -> io::Result<String> - Read a single line from
any reader implementing BufRead, trimming the
trailing newlineread_all_lines_from_reader<R: BufRead>(reader: R) -> io::Result<Vec<String>> - Read all lines from
a reader into a Vecwrite_to_writer<W: Write>(writer: &mut W, message: &str) -> io::Result<()> - Write a message to any writer implementing Writewriteln_to_writer<W: Write>(writer: &mut W, message: &str) -> io::Result<()> - Write a message with a newline to any writerwrite_and_flush<W: Write>(writer: &mut W, message: &str) -> io::Result<()> - Write a message and immediately flush the bufferwrite_error_to_writer<W: Write>(writer: &mut W, error: &str) -> io::Result<()> - Write an error message in the format "[ERROR] message" with a newlineNote: The functions are generic over BufRead and Write traits to make them testable without needing actual stdin/stdout.
use std::io::Cursor;
// Reading from a mock input
let input = Cursor::new("Hello, World!\n");
let line = read_line_from_reader(input)?;
assert_eq!(line, "Hello, World!");
// Reading multiple lines
let input = Cursor::new("Line 1\nLine 2\nLine 3\n");
let lines = read_all_lines_from_reader(input)?;
assert_eq!(
lines,
vec!["Line 1", "Line 2", "Line 3"]
);
// Writing to a buffer
let mut output = Vec::new();
write_to_writer(&mut output, "Hello")?;
assert_eq!(String::from_utf8(output).unwrap(), "Hello");
// Writing with newline
let mut output = Vec::new();
writeln_to_writer(&mut output, "Hello")?;
assert_eq!(
String::from_utf8(output).unwrap(),
"Hello\n"
);
// Writing an error message
let mut output = Vec::new();
write_error_to_writer(&mut output, "Something went wrong")?;
assert_eq!(
String::from_utf8(output).unwrap(),
"[ERROR] Something went wrong\n"
);reader.read_line(&mut buffer) to read a single linebuffer.trim_end_matches('\n') .trim_end_matches('\r') to strip line endings
for both Unix and Windowslines() iterator from BufRead automatically strips newlineswrite!(writer, "{}", message) or writer.write_all(message.as_bytes()) to writewriteln!(writer, "{}", message) to write with a newlinewriter.flush() to ensure buffered output is written immediatelyformat!("[ERROR] {}", error) or write!(writer, "[ERROR] {}\n", error)