Запись в файл с Append (false) не работает должным образом - PullRequest
0 голосов
/ 02 ноября 2019

Я учусь программировать на Rust и решил создать CLI для управления моей личной библиотекой. Я все еще работаю над быстрым доказательством концепции, прежде чем идти дальше, поэтому у меня есть все необходимое для работы.

Я сохраняю данные в файл с именем "books.json", используя std::fs и serde_json. Программа отлично работает в первый раз, когда я ее запускаю, но при втором запуске вместо перезаписи файла добавляются данные (в целях тестирования она добавит одну и ту же книгу дважды).

Вот код, который я написал до сих пор. Используя OpenOptions.append(false), не должен ли файл перезаписываться при записи в него?

use serde::{Deserialize, Serialize};
use serde_json::Error;
use std::fs;
use std::fs::File;
use std::io::Read;
use std::io::Write;

#[derive(Serialize, Deserialize)]
struct Book {
    title: String,
    author: String,
    isbn: String,
    pub_year: usize,
}

fn main() -> Result<(), serde_json::Error> {
    let mut file = fs::OpenOptions::new()
        .read(true)
        .write(true)
        .append(false)
        .create(true)
        .open("books.json")
        .expect("Unable to open");
    let mut data = String::new();
    file.read_to_string(&mut data);

    let mut bookshelf: Vec<Book> = Vec::new();
    if file.metadata().unwrap().len() != 0 {
        bookshelf = serde_json::from_str(&data)?;
    }

    let book = Book {
        title: "The Institute".to_string(),
        author: "Stephen King".to_string(),
        isbn: "9781982110567".to_string(),
        pub_year: 2019,
    };

    bookshelf.push(book);

    let j: String = serde_json::to_string(&bookshelf)?;

    file.write_all(j.as_bytes()).expect("Unable to write data");

    Ok(())
}

books.json после запуска программы дважды:

[{"title":"The Institute","author":"Stephen King","isbn":"9781982110567","pub_year":2019}]
[{"title":"The Institute","author":"Stephen King","isbn":"9781982110567","pub_year":2019},
{"title":"The Institute","author":"Stephen King","isbn":"9781982110567","pub_year":2019}]%

1 Ответ

0 голосов
/ 02 ноября 2019

Члены сообщества Rust Discord отметили, что при использовании OpenOptions указатель файла заканчивался в конце файла, когда я писал в него. Они предложили мне использовать fs :: read и fs :: write, и это сработало. Затем я добавил код для обработки случаев, когда файл еще не существовал.

Функция main() должна выглядеть примерно так:

fn main() -> std::io::Result<()> {
    let f = File::open("books.json");

    let _ = match f {
        Ok(file) => file,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => match File::create("books.json") {
                Ok(fc) => fc,
                Err(e) => panic!("Problem creating the file: {:?}", e),
            },
        },
    };

    let data = fs::read_to_string("books.json").expect("Unable to read file");

    let mut bookshelf: Vec<Book> = Vec::new();
    if fs::metadata("books.json").unwrap().len() != 0 {
        bookshelf = serde_json::from_str(&data)?;
    }

    let book = Book {
        title: "The Institute".to_string(),
        author: "Stephen King".to_string(),
        isbn: "9781982110567".to_string(),
        pub_year: 2019,
    };

    bookshelf.push(book);

    let json: String = serde_json::to_string(&bookshelf)?;

    fs::write("books.json", &json).expect("Unable to write file");

    println!("{}", &json);

    Ok(())
}
...