Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to delete the contents of a file before writing to it in Rust?

I wrote a bot that performs some network queries once every so often and dumps the latest state into a file stored on disk. This is my code:

let log_file = OpenOptions::new()
    .read(true)
    .write(true)
    .create(true)
    .open(&log_file_name)
    .unwrap();
serde_json::to_writer(
    log_file,
    &State {
        foo: self.foo,
        bar: self.bar
    },
)
.unwrap();

The issue is that, occasionally, the size of the newest state json will be smaller than the size of the previous state JSON. This leaves that portion of the previous state JSON that is longer than the new state JSON to remain in the log file:

{"foo": 1,"bar": 2}"baz": 3}

In the example above, "baz": 3} is the leftover data from the previous state JSON.

The question is: how can I rewrite the code so that I first flush all the contents of the file and then write the new state json?

I know deleting the file is a solution but I would prefer not to do that.

like image 745
Paul Razvan Berg Avatar asked Dec 18 '22 11:12

Paul Razvan Berg


1 Answers

You additionally need the truncate flag, which results in the file being truncated to length 0 if it already exists. Additionally, you should remove the read flag, since you are not actually reading from the log file.

Since write, create, truncate is a very common combination of flags, there is a shortcut: You don't need to use the more low-level OpenOptions interface, and can instead use File::create():

let log_file = File::create(&log_file_name).unwrap();

The implementation of File::create() simply spells out the long version using OpenOptions:

pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
    OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
}
like image 170
Sven Marnach Avatar answered Dec 29 '22 10:12

Sven Marnach