17

I can write binary code to file with Rust. However, when I create a file, the file created is a text file, not binary. I can create a binary file with C++ like this:

ofstream is("1.in", ofstream::binary | ofstream::out | ofstream:: trunc);

How about in Rust? This is my attempt:

struct IndexDataStructureInt {
    row: u32,
    key_value: u32,
}

let mut index_arr: Vec<IndexDataStructureInt> = Vec::new();
// doing something push 100 IndexDataStructureInt to index_arr
let mut fileWrite = File::create(tableIndexName).unwrap();
for i in 0..index_arr.len() {
    write!(
        fileWrite,
        "{:b}{:b}",
        index_arr[i].row, index_arr[i].key_value
    );
}

After running this code, it writes 200 u32 integer binary number to the file tableIndexName. However, the file size is not 800bytes. It is about 4KB.

3
  • 2
    Can you share the sample code you are currently using to write & read the file? What makes you think the file is not "binary"? Commented Dec 18, 2018 at 4:49
  • @harmic hi thank you for response. I add some code in my question. Commented Dec 18, 2018 at 5:34
  • Welcome to Stack Overflow! Idiomatic Rust uses snake_case for variables, methods, macros, and fields; UpperCamelCase for types and enum variants; and SCREAMING_SNAKE_CASE for statics and constants. Use file_write and table_index_name instead, please. Commented Dec 18, 2018 at 15:13

1 Answer 1

38

Rust's std::fs::File does not have a concept of opening files in text or binary mode. All files are opened as "binary" files, and no translation of characters such as line feed and carriage return is performed.

Your problem stems from using the write! macro. This macro is for formatting data into printable format, and should not be used if you want to write binary data. In fact the {:b} format specifier you have used will convert the value into a printable binary string of ASCII 1 and 0 characters.

Instead, use the functions provided by trait std::io::Write. This trait is implemented directly by File, or you can use a BufWriter for potentially better performance.

For example: here I am using write_all to write a slice of u8 to a file, then using read_to_end to read the same file back into a Vec.

use std::fs::File;
use std::io::prelude::*;

fn main() -> std::io::Result<()> {
    {
        let mut file = File::create("test")?;
        // Write a slice of bytes to the file
        file.write_all(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])?;
    }

    {
        let mut file = File::open("test")?;
        // read the same file back into a Vec of bytes
        let mut buffer = Vec::<u8>::new();
        file.read_to_end(&mut buffer)?;
        println!("{:?}", buffer);
    }

    Ok(())
}
Sign up to request clarification or add additional context in comments.

2 Comments

Why the unnecessary curly braces inside of main?
@Shepmaster The first pair of braces makes sure the file is closed before it's opened and read again. This is not strictly needed, since the code is using unbuffered I/O, so you would be able to read the file contents back even before the file is closed. However, this is kind of beside the point for this question, so I think the version including the braces is less confusing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.