OpenOptions în Rust

Fișiere: std::fs, File, OpenOptions Rust 1.0 (File::options: 1.58)

Deschide un fișier cu opțiuni alese: adăugare la final, creare dacă lipsește, doar dacă nu există etc.

Sintaxă
use std::fs::{File, OpenOptions};

OpenOptions::new()
    .read(true) .write(true) .append(true)
    .create(true) .create_new(true) .truncate(true)
    .open(cale) -> io::Result<File>

File::options()  // la fel ca OpenOptions::new()

Ce face OpenOptions

OpenOptions este un „constructor” pentru deschiderea fișierelor. Pornești cu OpenOptions::new() (sau File::options(), aceeași valoare), alegi opțiunile cu metode înlănțuite și termini cu open(cale), care returnează un File.

Opțiuni: read(true) pentru citire, write(true) pentru scriere, append(true) pentru adăugare la final (implică scriere), create(true) creează fișierul dacă lipsește, create_new(true) îl creează și dă eroare AlreadyExists dacă există, truncate(true) îl golește la deschidere.

File::open este read(true); File::create este write(true).create(true).truncate(true). Pentru un fișier jurnal folosești append(true).create(true).

Ce returnează

open returnează io::Result<File>; celelalte metode returnează &mut OpenOptions, pentru înlănțuire.

Exemple

Exemplul 1: Jurnal: adaugă la final, creează dacă lipsește

Fiecare apel deschide fișierul în mod append, deci liniile vechi rămân.

use std::fs::{self, OpenOptions};
use std::io::Write;

fn scrie_jurnal(mesaj: &str) -> std::io::Result<()> {
    let mut f = OpenOptions::new().append(true).create(true).open("aplicatie.log")?;
    writeln!(f, "{mesaj}")
}

fn main() -> std::io::Result<()> {
    scrie_jurnal("pornire")?;
    scrie_jurnal("utilizator: ana")?;
    scrie_jurnal("oprire")?;
    print!("{}", fs::read_to_string("aplicatie.log")?);
    Ok(())
}

Rezultat

pornire
utilizator: ana
oprire

Exemplul 2: create_new: nu suprascrie un fișier existent

use std::fs::File;
use std::io::{ErrorKind, Write};

fn main() -> std::io::Result<()> {
    for incercare in 1..=2 {
        match File::options().write(true).create_new(true).open("factura_001.txt") {
            Ok(mut f) => {
                writeln!(f, "Factura 001: 120 lei")?;
                println!("încercarea {incercare}: factură creată");
            }
            Err(e) if e.kind() == ErrorKind::AlreadyExists => {
                println!("încercarea {incercare}: factura există deja, nu o suprascriu");
            }
            Err(e) => return Err(e),
        }
    }
    Ok(())
}

Rezultat

încercarea 1: factură creată
încercarea 2: factura există deja, nu o suprascriu

Exemplul 3: Citire și scriere în același fișier

use std::fs::{self, OpenOptions};
use std::io::{Read, Seek, SeekFrom, Write};

fn main() -> std::io::Result<()> {
    fs::write("contor.txt", "41")?;
    let mut f = OpenOptions::new().read(true).write(true).open("contor.txt")?;

    let mut text = String::new();
    f.read_to_string(&mut text)?;
    let nou = text.trim().parse::<u32>().unwrap_or(0) + 1;

    f.seek(SeekFrom::Start(0))?;
    f.set_len(0)?;
    write!(f, "{nou}")?;
    println!("contor: {}", fs::read_to_string("contor.txt")?);
    Ok(())
}

Rezultat

contor: 42

Greșeli frecvente

  • Scrii OpenOptions::new().open(cale) fără nicio opțiune: eroarea InvalidInput. Trebuie cel puțin read, write sau append.
  • Folosești create(true) fără write(true) sau append(true): deschiderea eșuează.
  • Combini append(true) cu truncate(true): nu are sens și dă eroare.

Comenzi înrudite

  • File: Un fișier deschis: File::open îl deschide pentru citire, File::create îl creează (sau golește) pentru scriere.
  • fs::write: Scrie tot conținutul dat într-un fișier, creându-l dacă nu există și înlocuindu-l dacă există.
  • io::Write: Trait-ul oricărei destinații de octeți: write_all scrie tot bufferul, flush golește memoria tampon; permite write!.
  • io::Error: Eroarea operațiilor de intrare/ieșire; kind() dă categoria (NotFound, PermissionDenied…), iar new() creează una proprie.