Best way to replace text in a file

Hi all,

Long time no see! I have a seemingly simple question, but I was a bit stumped as to how best to do it.

I have a database of bibliographic records, and I want to edit a record in place ideally. I'm using my homemade refer crate to iterate over the records (that's not a plug but if anyone can cast their eye over the crate I'd be grateful). I want to open an editor, allow a user to make their changes to the record, and then save it in place in the file. Something like this (very untested code):

use refer::{Reader, Writer};

let mut reader = Reader::from_path("/path/to/database")?;

// my naive thought is to open a write connection to the same file
let file = OpenOptions::new()
    .write(true)
    .append(true)
    .open("/path/to/database")?;

let writer = Writer::new(file);

for result in reader.records() {
    let record = result?;

    if (this_is_the_record_to_edit) {
        let updated_record_string = update_record(record); // ficticious update_record() function
        writer.write_record(vec![updated_record_string])?;
    } else {
        writer.write_record(vec![record.to_string()])?;
    }
}

So this obviously overwrites the whole database every time that we edit a single record, not ideal. I just have limited knowledge of I/O to limit my editing to a single portion of the input file.

Is it possible to edit the file in place?. I am guessing this requires iterating over all of the records, finding the record of interest, finding the start and end byte of this record(?) and then seeking to that place? Any better/concrete ideas with/without (pseudo)code would be incredible. Thanks for the help Rust community!

Cheers!
M

Yes, files can be partially updated by seeking to a given starting position and writing any number of bytes. However, this is not a text file handling question at this point.

Typically, editors suited for human-readable "plain text" documents assume that any such file is small compared to the capabilities of today's hardware, and so such editors will simply read the entire file in operative memory, edit it in memory, and then dump the whole contents again upon save, overwriting the old file completely.

If your concern is that you have too many records for this to be done in reasonable time (e.g. you have several GBs worth of records), then you'll need to use a real database which can efficiently handle finding and partially updating data. Most of the time you'll observe me recommend SQLite3, a small embeddable database which is a single-file C library and which has type-safe Rust bindings.

7 Likes

You are right, I hadn't really thought about it like that. The database isn't big (or at least won't be GB's for a loong time). So I'll probably find the line number of the record of interest, and jump to that in the editor. I think that makes most sense. Thanks for the help!

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.