Rust 1.x'te dosyaları okumanın ve yazmanın fiili yolu nedir?


136

Rust nispeten yeni olduğundan, dosya okuma ve yazmanın çok fazla yolunu gördüm. Birçoğu, blogları için birinin oluşturduğu son derece dağınık snippet'ler ve bulduğum örneklerin% 99'u (Stack Overflow'da bile) artık çalışmayan kararsız yapılardan. Rust artık kararlı olduğuna göre, dosyaları okumak veya yazmak için basit, okunabilir, panik yapmayan bir pasaj nedir?

Bu, bir metin dosyasını okuma açısından işe yarayan bir şeye en yakın olanıdır, ancak sahip olmam gereken her şeyi dahil ettiğimden oldukça emin olsam da hala derlemiyor. Bu, Google + 'da her yerde bulduğum bir parçacığa dayanıyor ve değiştirdiğim tek şey, eskisinin BufferedReaderartık sadece BufReader:

use std::fs::File;
use std::io::BufReader;
use std::path::Path;

fn main() {
    let path = Path::new("./textfile");
    let mut file = BufReader::new(File::open(&path));
    for line in file.lines() {
        println!("{}", line);
    }
}

Derleyici şikayet ediyor:

error: the trait bound `std::result::Result<std::fs::File, std::io::Error>: std::io::Read` is not satisfied [--explain E0277]
 --> src/main.rs:7:20
  |>
7 |>     let mut file = BufReader::new(File::open(&path));
  |>                    ^^^^^^^^^^^^^^
note: required by `std::io::BufReader::new`

error: no method named `lines` found for type `std::io::BufReader<std::result::Result<std::fs::File, std::io::Error>>` in the current scope
 --> src/main.rs:8:22
  |>
8 |>     for line in file.lines() {
  |>                      ^^^^^

Özetlemek gerekirse, aradığım şey:

  • kısalık
  • okunabilirliği
  • olası tüm hataları kapsar
  • panik yapmaz

Dosyayı nasıl okumak istersiniz? Gösterdiğiniz gibi, satır satır ister misiniz? Hepsini tek bir dizede mi istiyorsun? "Bir dosyayı okumanın" birden fazla yolu vardır.
Shepmaster

Her iki şekilde de iyidir. Kasıtlı olarak açık bıraktım. Hepsi tek bir dizede toplanırsa, onu bir Vec <String> 'e bölmek önemsiz olur ve bunun tersi de geçerlidir. Çözüm arayışımın bu noktasında, işe yarayan zarif, güncel Rust dosyası G / Ç kodunu görmekten mutlu olacağım.
Jared

3
Özellik hatası ( std::io::Read) ile ilgili olarak, Rust'ta kullanmayı beklediğiniz özellikleri açıkça içe aktarmanız gerektiğini unutmayın ; bu yüzden burada use std::io::Readbir use std::io::{Read,BufReader}eksiksiniz (iki kullanımı bir araya getirmek için bir olabilir)
Matthieu M.

Yanıtlar:


198

Burada gösterdiğim işlevlerin hiçbiri kendi başına paniğe kapılmıyor, ancak kullanıyorum expectçünkü uygulamanıza ne tür bir hata işlemenin en iyi uyacağını bilmiyorum. Git okundu Dil Programlama Rust 'ın hata işleme faslını uygun kendi programında başarısızlık nasıl işleneceğini anlamak için.

Pas 1.26 ve sonrası

Altta yatan ayrıntılarla ilgilenmek istemiyorsanız, okuma ve yazma için tek satırlık işlevler vardır.

Bir dosyayı bir String

use std::fs;

fn main() {
    let data = fs::read_to_string("/etc/hosts").expect("Unable to read file");
    println!("{}", data);
}

Bir dosyayı bir Vec<u8>

use std::fs;

fn main() {
    let data = fs::read("/etc/hosts").expect("Unable to read file");
    println!("{}", data.len());
}

Bir dosya yazın

use std::fs;

fn main() {
    let data = "Some data!";
    fs::write("/tmp/foo", data).expect("Unable to write file");
}

Rust 1.0 ve sonrası

Bu formlar, bir Stringveya Vecsizin için ayıran tek satırlık işlevlerden biraz daha ayrıntılıdır , ancak tahsis edilen verileri yeniden kullanabileceğiniz veya mevcut bir nesneye ekleyebileceğiniz için daha güçlüdür.

Verileri okumak

Bir dosyanın okunması iki temel parça gerektirir: Fileve Read.

Bir dosyayı bir 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);
}

Bir dosyayı bir Vec<u8>

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());
}

Bir dosya yazın

Bir dosya yazmak benzerdir, ancak Writeözelliği kullanmamız ve her zaman bayt yazmamız dışında. A String/ ' &stryi bayta şu şekilde dönüştürebilirsiniz 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");
}

Arabellekli G / Ç

Kullanmak topluluktan bir itme biraz hissetti BufReaderve BufWriterbunun yerine bir dosyadan düz okuma

Arabelleğe alınmış bir okuyucu (veya yazıcı), G / Ç isteklerinin sayısını azaltmak için bir arabellek kullanır. Örneğin, diske 256 kez erişmek yerine 256 baytı okumak için diske bir kez erişmek çok daha verimlidir.

Bununla birlikte, arabelleğe alınmış bir okuyucunun / yazıcının tüm dosyayı okurken faydalı olacağına inanmıyorum. read_to_endverileri biraz büyük parçalar halinde kopyalıyor gibi görünüyor, bu nedenle aktarım doğal olarak daha az G / Ç talebiyle birleştirilebilir.

İşte onu okumak için kullanmanın bir örneği:

use std::fs::File;
use std::io::{BufReader, Read};

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);
}

Ve yazmak için:

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

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");
}

BufReaderSatır satır okumak istediğinizde A daha kullanışlıdır:

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);
    }
}

2
Buna dayandıracak pek bir şeyim yok, ancak bunu araştırırken, doğrudan bir dosyadan bir dizeye okumak yerine, BufReader ve BufWriter'ı kullanmak için topluluktan biraz baskı hissettim. Cevabınızda gösterdiğiniz "daha klasik" versiyona kıyasla bu nesneler veya bunları kullanmanın artıları ve eksileri hakkında çok şey biliyor musunuz?
Jared

@TheDaleks Sorunuzu takip etmiyorum. b"foobar"bir bayt dizisine ( &[u8; N]) başvuru oluşturmak için değişmez bir bilgidir . Bu nedenle, değişmezdir. Size daha basit bir şekilde yapamayacağınız hiçbir şey vermez.
Shepmaster

@Shepmaster Bazen kodlanmış bir dizge yerine bir bayt dizisine sahip olmak avantajlıdır; örneğin, dosyaları bir noktadan diğerine taşıyan bir uygulama yapmak istiyorsanız, uygulamanın işlediği yürütülebilir dosyaları bozmamak için ham baytlara sahip olmanız gerekir.
Dalekler

@TheDaleks evet, bu yüzden bu cevap a'nın Vec<u8>okuma ve yazma için nasıl kullanılacağını açıklıyor . Bunlar ham baytlardır.
Shepmaster
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.