How to read subset of lines (like tail) from a file

Currently, I'm using this function in my code:

fn lines_from_file(filename: impl AsRef<Path>) -> Vec<String> {
    let file = File::open(filename).expect("no such file");
    let buf = BufReader::new(file);
    buf.lines().map(|l| l.expect("Could not parse line")).collect()
}

How can I safely read the last x lines only?

I don't really know how to help you rather than providing the code I'd write for it, so:

fn read_last_n_lines(path: impl AsRef<Path>, n: usize) -> Vec<String> {
    // it's simpler to use the provided helper function than dealing with the File ourselves
    let s = std::fs::read_to_string(path).unwrap();
   
    // we collect all the lines into a vec
    let s = s.lines().collect::<Vec<_>>();
   
    // then take only the last n lines
    s[s.len().saturating_sub(n)..s.len()].iter().map(|&s| String::from(s)).collect()
}

If there's anything unclear about the code above, feel free to ask me any questions about it

Still trying to understand some of the lower levels of rust. Wouldn't s contain the entire contents of the file? Most times that's not problematic, but I'm work with potentially files large than my RAM.

Yes. If you want to actually read only the last n lines of data from the file I think you'll have to write the code for that yourself. As far as I know the standard library doesn't have any facilities for reading lines from the end of a file back towards the beginning.

I ended up using rev_buffer_reader and only take certain number items with the iterator

fn lines_from_file(file: &File, limit: usize) -> Vec<String> {
    let buf = RevBufReader::new(file);
    buf.lines().take(limit).map(|l| l.expect("Could not parse line")).collect()
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.