Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading from file at different offsets using Rust

Tags:

file

rust

I am working on a project that involves reading different information from a file at different offsets.

Currently, I am using the following code:

// ------------------------ SECTORS PER CLUSTER ------------------------

// starts at 13
opened_file.seek(SeekFrom::Start(13)).unwrap();
let aux: &mut [u8] = &mut [0; 1];
let _buf = opened_file.read_exact(aux);

// ------------------------ RESERVED SECTORS ------------------------

// starts at 14
opened_file.seek(SeekFrom::Start(14)).unwrap();
let aux: &mut [u8] = &mut [0; 2];
let _buf = opened_file.read_exact(aux);

But as you can see, I need to create a new buffer of the size I want to read every time. I can't specify it directly as a parameter of the function.

I created a struct but I could not make a struct of all the different pieces of data I wanted. For example:

struct FileStruct {
    a1: &mut [u8] &mut [0; 1],
    a2: &mut [u8] &mut [0; 2],
}

Which are the types that are required for the read_exact method to work?

Is there a more effective way to read information from different offsets of a file without having to repeatedly copy-paste these lines of code for every piece of information I want to read from the file? Some sort of function, Cursor, or Vector to easily move around the offset? And a way to write this info into struct fields?

like image 957
LittleBigTech Avatar asked Oct 31 '25 05:10

LittleBigTech


1 Answers

The easiest way is to have a struct of owned arrays, then seek and read into the struct.

use std::io::{self, prelude::*, SeekFrom};

#[derive(Debug, Clone, Default)]
struct FileStruct {
    a1: [u8; 1],
    a2: [u8; 2],
}

fn main() -> io::Result<()> {
    let mut file_struct: FileStruct = Default::default();
    let mut opened_file = unimplemented!(); // open file somehow
    opened_file.seek(SeekFrom::Start(13))?;
    opened_file.read_exact(&mut file_struct.a1)?;
    opened_file.seek(SeekFrom::Start(14))?;
    opened_file.read_exact(&mut file_struct.a2)?;
    println!("{:?}", file_struct);
    Ok(())
}

Playground link

This is still decently repetitive, so you can make a seek_read function to reduce the repetition:

use std::io::{self, prelude::*, SeekFrom};

#[derive(Debug, Clone, Default)]
struct FileStruct {
    a1: [u8; 1],
    a2: [u8; 2],
}

fn seek_read(mut reader: impl Read + Seek, offset: u64, buf: &mut [u8]) -> io::Result<()> {
    reader.seek(SeekFrom::Start(offset))?;
    reader.read_exact(buf)?;
    Ok(())
}

fn main() -> io::Result<()> {
    let mut file_struct: FileStruct = Default::default();
    let mut opened_file = unimplemented!(); // open file somehow
    seek_read(&mut opened_file, 13, &mut file_struct.a1)?;
    seek_read(&mut opened_file, 14, &mut file_struct.a2)?;
    println!("{:?}", file_struct);
    Ok(())
}

Playground link

The repetition can be lowered even more by using a macro:

use std::io::{self, prelude::*, SeekFrom};

#[derive(Debug, Clone, Default)]
struct FileStruct {
    a1: [u8; 1],
    a2: [u8; 2],
}

macro_rules! read_offsets {
    ($file: ident, $file_struct: ident, []) => {};
    ($file: ident, $file_struct: ident, [$offset: expr => $field: ident $(, $offsets: expr => $fields: ident)*]) => {
        $file.seek(SeekFrom::Start($offset))?;
        $file.read_exact(&mut $file_struct.$field)?;
        read_offsets!($file, $file_struct, [$($offsets => $fields),*]);
    }
}

fn main() -> io::Result<()> {
    let mut file_struct: FileStruct = Default::default();
    let mut opened_file = unimplemented!(); // open file somehow
    read_offsets!(opened_file, file_struct, [13 => a1, 14 => a2]);
    println!("{:?}", file_struct);
    Ok(())
}

Playground link

like image 128
Aplet123 Avatar answered Nov 02 '25 02:11

Aplet123