Seek
The Seek trait in std::io moves a byte cursor to an arbitrary offset within a stream, enabling random-access reads and writes in files and in-memory buffers.
Trait Definition and SeekFrom
pub enum SeekFrom {
Start(u64),
End(i64),
Current(i64),
}
pub trait Seek {
fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64>;
// Provided methods:
fn rewind(&mut self) -> std::io::Result<()>;
fn stream_position(&mut self) -> std::io::Result<u64>;
}
Calling seek(&mut self, pos) repositions the stream cursor and returns Ok(new_position) measured in bytes from the start of the stream.
| Variant / Method | Behavior |
|---|---|
SeekFrom::Start(n) |
Sets cursor to absolute byte offset n from the beginning of the stream |
SeekFrom::Current(delta) |
Moves cursor by signed delta bytes relative to its current position |
SeekFrom::End(delta) |
Moves cursor by signed delta bytes relative to the end of the stream |
.rewind() |
Equivalent to .seek(SeekFrom::Start(0)) |
.stream_position() |
Equivalent to .seek(SeekFrom::Current(0)); returns current byte offset |
Random-Access I/O with std::io::Cursor
While network sockets (TcpStream) and pipes are sequential and do not implement Seek, std::fs::File and std::io::Cursor<T> implement Seek alongside Read and Write:
use std::io::{self, Cursor, Read, Seek, SeekFrom, Write};
fn main() -> io::Result<()> {
let mut stream = Cursor::new(Vec::new());
stream.write_all(b"HEADER:0000:PAYLOAD")?;
// Jump to byte offset 7 to overwrite the 4-byte length field:
stream.seek(SeekFrom::Start(7))?;
stream.write_all(b"0007")?;
// Read the last 7 bytes using SeekFrom::End:
stream.seek(SeekFrom::End(-7))?;
let mut tail = String::new();
stream.read_to_string(&mut tail)?;
// Rewind to the start to read the entire modified stream:
stream.rewind()?;
let mut full = String::new();
stream.read_to_string(&mut full)?;
println!("Tail: {tail}");
println!("Full: {full}");
Ok(())
}
Tail: PAYLOAD
Full: HEADER:0007:PAYLOAD
Combining Read + Seek in Binary Parsers
Formats with footer indexes (such as ZIP archives or Parquet files) typically bound their input stream by R: Read + Seek so the parser can seek to the end of the stream (SeekFrom::End), read the central directory offset, and then seek directly to specific compressed entries without scanning the entire file sequentially.