Hai bisogno di due pezzi fondamentali: File
e Read
.
Se volete leggere tutto ad una String
:
use std::fs::File;
use std::io::Read;
fn main() {
let mut data = String::new();
let mut f = File::open("/etc/hosts").expect("Unable to open file");
f.read_to_string(&mut data).expect("Unable to read string");
println!("{}", data);
}
Se volete leggere tutto come una serie di byte:
use std::fs::File;
use std::io::Read;
fn main() {
let mut data = Vec::new();
let mut f = File::open("/etc/hosts").expect("Unable to open file");
f.read_to_end(&mut data).expect("Unable to read data");
println!("{}", data.len());
}
Nessuno del panico funzioni per conto proprio, ma Sto usando expect
perché non so quale tipo di gestione degli errori si adatta meglio alla tua applicazione.
Queste sono leggermente più verbose delle versioni ipotetiche che allocano uno String
o Vec
per voi, ma sono più potenti in quanto è possibile riutilizzare i dati allocati o accodare a un oggetto esistente. Scrivere un piccolo wrapper che assegna l'oggetto per te è banale e potrebbe essere un'aggiunta ergonomica in futuro.
Scrivere un file è lo stesso, tranne che è sempre eseguito come byte. È possibile convertire un String
/&str
di byte con as_bytes
:
use std::fs::File;
use std::io::Write;
fn main() {
let data = "Some data!";
let mut f = File::create("/tmp/foo").expect("Unable to create file");
f.write_all(data.as_bytes()).expect("Unable to write data");
}
mi sono sentito un po 'di una spinta da parte della comunità di usare BufReader
e BufWriter
invece di leggere direttamente da un file
A il lettore (o lo scrittore) bufferizzato utilizza un buffer per ridurre il numero di richieste IO. Ad esempio, è molto più efficiente accedere al disco una volta per leggere 256 byte invece di accedere al disco 256 volte.
Detto questo, non credo che un lettore/scrittore bufferizzato sarà utile quando si legge l'intero file.read_to_end
sembra copiare i dati in blocchi piuttosto grandi, quindi il trasferimento potrebbe già essere naturalmente riunito in un numero inferiore di richieste di I/O.
Ecco un esempio di utilizzo:
use std::fs::File;
use std::io::{Read, BufReader};
fn main() {
let mut data = String::new();
let f = File::open("/etc/hosts").expect("Unable to open file");
let mut br = BufReader::new(f);
br.read_to_string(&mut data).expect("Unable to read string");
println!("{}", data);
}
E per la scrittura:
use std::fs::File;
use std::io::{Write, BufWriter};
fn main() {
let data = "Some data!";
let f = File::create("/tmp/foo").expect("Unable to create file");
let mut f = BufWriter::new(f);
f.write_all(data.as_bytes()).expect("Unable to write data");
}
Un BufReader
è più utile quando si desidera leggere riga per riga:
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() {
let f = File::open("/etc/hosts").expect("Unable to open file");
let f = BufReader::new(f);
for line in f.lines() {
let line = line.expect("Unable to read line");
println!("Line: {}", line);
}
}
Nel Ru notturno st, ci sono funzioni di una sola riga per la lettura e la scrittura:
#![feature(fs_read_write)]
use std::fs;
fn main() {
let data = fs::read_string("/etc/hosts").expect("Unable to open file");
println!("{}", data);
}
#![feature(fs_read_write)]
use std::fs;
fn main() {
let data = fs::read("/etc/hosts").expect("Unable to open file");
println!("{}", data.len());
}
#![feature(fs_read_write)]
use std::fs;
fn main() {
let data = "Some data!";
fs::write("/tmp/foo", data).expect("Unable to write data");
}
Mi aspetto che questi diventino l'alternativa popolare una volta che sono stabilizzati.
Come si desidera leggere il file? Lo vuoi line-by-line, come hai mostrato? Lo vuoi tutto in una stringa? C'è più di un modo per "leggere un file". – Shepmaster
In entrambi i casi va bene. L'ho lasciato aperto intenzionalmente. Se viene raccolto tutto in una stringa, la suddivisione in un Vec sarebbe banale e viceversa. A questo punto della mia ricerca di soluzioni, sarò felice di vedere solo un codice I/O di file ruggine aggiornato e aggiornato che funziona. –
Per quanto riguarda l'errore del tratto ('std :: io :: Read'), si noti che in Rust è necessario importare i tratti che si prevede utilizzino * esplicitamente *; quindi qui manca un 'use std :: io :: Read' (che potrebbe essere un' use std :: io :: {Read, BufReader} 'per unire i due usi insieme) –