Using read_until for a sequence of bytes

Hi,

I'm looking to read a file until the end of the data (Note the true EOF; a literal sequence _eof), but have found trouble defining more than a single byte using read_until. Right now it stops prematurely due to the presence of underscores preceding this, but does read and output as expected otherwise:

use hex::ToHex;
use std::fs::File;
use std::io::{BufRead, BufReader, Seek, SeekFrom};

fn main() {
let filename = "./test.bin";
let offset = 0xD2F0;
// let eof = "\x5f\x65\x6f\x66";

let file = File::open(filename).unwrap();
let mut file = BufReader::new(file);
let mut data = Vec::new();
file.seek(SeekFrom::Start(offset)).unwrap();
file.read_until(b'\x5f', &mut data).unwrap();    
println!(
    "{:#?}", 
    data.encode_hex::<String>(),);

}

Is there a more sensible way to accomplish this? I've tried altering read_until in a few different fashions only to find it's looking for a single byte, but feel I'm approaching the issue in the wrong way.

Thank you

This is a good start, you just have to check the next characters are what you need, and if not, keep reading.

use std::fs::File;
use std::io::{BufRead, BufReader, Read, Seek, SeekFrom};

fn main() {
    let filename = "./test.bin";
    let offset = 0xD2F0;
    let eof = b"\x5f\x65\x6f\x66";

    let file = File::open(filename).unwrap();
    let mut file = BufReader::new(file);
    let mut data = Vec::new();
    file.seek(SeekFrom::Start(offset)).unwrap();
    loop {
        file.read_until(eof[0], &mut data).unwrap();
        let mut buf = [0; 3];
        file.read_exact(&mut buf).unwrap();
        data.extend_from_slice(&buf);
        if &buf == &eof[1..] {
            break;
        }
    }
    println!("{:#?}", data);
}

Or you can use BufRead::fill_buf, BufRead::consume, and memchr directly.

use std::fs::File;
use std::io::{BufRead, BufReader, Seek, SeekFrom};

fn main() {
    let filename = "./test.bin";
    let offset = 0xD2F0;
    let eof = b"\x5f\x65\x6f\x66";

    let file = File::open(filename).unwrap();
    let mut file = BufReader::new(file);
    let mut data = Vec::new();
    file.seek(SeekFrom::Start(offset)).unwrap();

    let finder = memchr::memmem::Finder::new(eof);
    loop {
        let buf = file.fill_buf().unwrap();

        if let Some(i) = finder.find(buf) {
            data.extend_from_slice(&buf[..i + eof.len()]);
            file.consume(i + eof.len());
            break;
        }

        data.extend_from_slice(buf);
        let len = buf.len();
        file.consume(len);
    }
    println!("{:#?}", data);
}
3 Likes

This is perfect, thank you!! And thank you for the explanation of each option; that was where I felt stuck the most. This is my first venture into Rust and feel much more assured with your break down.

1 Like