0

I'm looking for help/examples on how to read a relatively large (>12M) binary file of double precision numbers into a rust array. I have metadata on the number of f64 values in the file.

I've read on this and seen the byteorder crate but did not find the documentation/examples particularly helpful.

This is not something that needs to be BufRead, since that likely won't help performance.

Thank you!

Herohtar
  • 5,347
  • 4
  • 31
  • 41
DPGraham4401
  • 178
  • 1
  • 12
  • Is there a particular difficulty you are facing? Reading 8 bytes into buffer and converting it into f64 with bincode seems pretty straitforward. – Maxim Gritsenko Sep 15 '21 at 05:27
  • Easiest way to do it is with [`read_f64_into`](https://docs.rs/byteorder/1.4.3/byteorder/trait.ByteOrder.html#method.read_f64_into) from the `byteorder` crate. – Jmb Sep 15 '21 at 07:12

1 Answers1

2

The easiest way to do it is to read 8 bytes and convert it to f64 using one of the f64::from_byte-order_bytes() methods:

These methods are used like that:

let mut buffer = [0u8; 8]; // the buffer can be reused!
reader.read_exact(&mut buffer) ?;
let float = f64::from_be_bytes(buffer);

So you can either read the file 8 bytes at a time or on some larger chunks:

fn main() -> Result<(), Box<dyn Error>> {
    let file = File::open("./path/to/file")?;
    let mut reader = BufReader::new(file);

    let mut buffer = [0u8; 8];
    loop {
        if let Err(e) = reader.read_exact(&mut buffer) {
            // if you know how many bytes are expected, then it's better not to rely on `UnexpectedEof`!
            if e.kind() == ErrorKind::UnexpectedEof {
                // nothing more to read
                break;
            }

            return Err(e.into());
        }

        // or use `from_le_bytes()` depending on the byte-order
        let float = f64::from_be_bytes(buffer);
        //do something with the f64
        println!("{}", float);

    }

    Ok(())
}

If you don't mind adding an additional dependency to your project, then you can also use the ByteOrder crate which has convenience methods to read whole slices:

use byteorder::{ByteOrder, LittleEndian};

let mut bytes = [0; 32]; // the buffer you've read the file into
let mut numbers_got = [0.0; 4];

LittleEndian::read_f64_into(&bytes, &mut numbers_got);
assert_eq!(numbers_given, numbers_got)
Svetlin Zarev
  • 14,713
  • 4
  • 53
  • 82