How to deserialize distinct objects from the same file

I would like to serialize and then deserialize distinct objects in distinct parts of the same file, in RON format. So, I wrote this sample code:

use std::error::Error;
use std::fs::File;
use std::io::{BufReader, BufWriter, Read, Seek, Write};

const PATH: &str = "data.ron";
const SEPARATOR: &[u8] = b" something ";

fn serialize() -> Result<(), Box<dyn Error>> {
    let file = File::create(PATH)?;
    let mut writer = BufWriter::new(file);
    ron::ser::to_writer(&mut writer, &"Hi")?;
    writer.write(SEPARATOR)?;
    ron::ser::to_writer(&mut writer, &12.30)?;
    println!("Wrote file: {}", PATH);
    Ok(())
}

fn deserialize() -> Result<(), Box<dyn Error>> {
    let file = File::open(PATH)?;
    let mut reader = BufReader::new(file);
    let word: String = ron::de::from_reader(&mut reader)?;
    reader.seek(std::io::SeekFrom::Current(SEPARATOR.len() as i64))?;
    let number: f64 = ron::de::from_reader(&mut reader)?;
    println!("Read back: {}, {}", word, number);
    Ok(())
}

fn main() -> Result<(), Box<dyn Error>> {
    serialize()?;
    deserialize()?;
    Ok(())
}

It can be compiled and run with these dependencies:

ron = "0.8"
serde = "1.0.219"

It prints this to the console:

Wrote file: data.ron
Error: SpannedError { code: TrailingCharacters, position: Position { line: 1, col: 6 } }

The generated file contains this:

"Hi" something 12.3

A first problem is that, if I set the dependency ron = "0.9" or ron = "0.10.1", the program cannot be compiled anymore, because the trait bound `BufWriter<File>: std::fmt::Write` is not satisfied..
However, the biggest problem is that SpannedError that I get after having deserialized the string "Hi".

EDIT:
I solved the issue by generating this data.ron file:

7 "Hello" something 4 12.3

In it, before every RON-serialized object, there is its length in bytes. When I need to deserialize an object, first I read its declared length, then I read a sequence of bytes of such a length, and then I use the "ron" library to deserialize that byte array.

As I interpret the grammar, RON expects the file to contain a single data entry, with optional preceding and trailing whitespace. What you are doing creates a file that does not contain a valid RON stream, even though it begins with a RON value.

I can think of a few ways to address that, but the simplest one is probably to rearrange the problem so that you serialize a single value. Since ron supports the entire Serde data model, you can use tuples:

use std::error::Error;
use std::fs::File;
use std::io::{BufReader, Write};

const PATH: &str = "data.ron";

fn serialize() -> Result<(), Box<dyn Error>> {
    let value = ("Hi", 12.30);

    let ron = ron::ser::to_string(&value)?;
    let mut file = File::create(PATH)?;
    file.write_all(ron.as_bytes())?;

    println!("Wrote file: {}", PATH);
    Ok(())
}

fn deserialize() -> Result<(), Box<dyn Error>> {
    let file = File::open(PATH)?;
    let mut reader = BufReader::new(file);
    let value: (String, f64) = ron::de::from_reader(&mut reader)?;
    let (word, number) = value;
    println!("Read back: {}, {}", word, number);
    Ok(())
}

fn main() -> Result<(), Box<dyn Error>> {
    serialize()?;
    deserialize()?;
    Ok(())
}

If your requirements are such that you must serialize two separate streams, serialize them to strings, frame them accordingly, and then separate them back out into separate strings before decoding them.

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.