io::Read în Rust

Trait-ul oricărei surse de octeți (fișier, stdin, rețea): read_to_string și read_to_end citesc tot ce a rămas.

Sintaxă
use std::io::Read;

fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize>
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize>

Ce face io::Read

Read are o singură metodă obligatorie, read(&mut buf), care umple o parte din buf și spune câți octeți a citit (0 = sfârșit). Pe baza ei, trait-ul oferă metode mai comode.

read_to_string(&mut s) citește tot ce a rămas și adaugă la s; dă eroare dacă datele nu sunt UTF-8. read_to_end(&mut v) adaugă toți octeții la un Vec<u8>. Amândouă returnează numărul de octeți citiți. Trait-ul trebuie importat: use std::io::Read;.

Funcțiile care primesc impl Read pot lucra cu orice sursă: fișier, io::stdin(), &[u8] din memorie, conexiune de rețea.

Parametri

Parametru Descriere
buf Locul în care se pun datele citite.

Ce returnează

io::Result<usize>: numărul de octeți citiți.

Exemple

Exemplul 1: read_to_string și read_to_end

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

fn main() -> io::Result<()> {
    fs::write("poezie.txt", "Pe lângă plopii fără soț\n")?;

    let mut text = String::new();
    let n = File::open("poezie.txt")?.read_to_string(&mut text)?;
    println!("{n} octeți: {text:?}");

    let mut octeti = Vec::new();
    File::open("poezie.txt")?.read_to_end(&mut octeti)?;
    println!("primii 8 octeți: {:?}", &octeti[..8]);
    Ok(())
}

Rezultat

30 octeți: "Pe lângă plopii fără soț\n"
primii 8 octeți: [80, 101, 32, 108, 195, 162, 110, 103]

Exemplul 2: O funcție care merge cu orice sursă

numara_vocale primește impl Read: o apelăm cu un fișier și cu octeți din memorie.

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

fn numara_vocale(mut sursa: impl Read) -> io::Result<usize> {
    let mut text = String::new();
    sursa.read_to_string(&mut text)?;
    Ok(text.chars().filter(|c| "aeiouăâî".contains(c.to_ascii_lowercase())).count())
}

fn main() -> io::Result<()> {
    fs::write("text.txt", "Ana are mere")?;
    println!("din fișier: {}", numara_vocale(File::open("text.txt")?)?);
    println!("din memorie: {}", numara_vocale("Bună ziua".as_bytes())?);
    Ok(())
}

Rezultat

din fișier: 6
din memorie: 5

Exemplul 3: Citire în bucăți cu read

Bufferul are 4 octeți, deci datele vin pe rând. Ultima bucată este mai scurtă.

use std::io::{self, Read};

fn main() -> io::Result<()> {
    let mut sursa: &[u8] = b"0123456789";
    let mut buf = [0u8; 4];
    loop {
        let n = sursa.read(&mut buf)?;
        if n == 0 {
            break;
        }
        println!("am citit {n}: {:?}", String::from_utf8_lossy(&buf[..n]));
    }
    Ok(())
}

Rezultat

am citit 4: "0123"
am citit 4: "4567"
am citit 2: "89"

Greșeli frecvente

  • Presupui că read umple tot bufferul: poate returna mai puțini octeți. Folosește valoarea returnată sau read_exact.
  • Uiți use std::io::Read: metodele nu sunt găsite pe File.

Comenzi înrudite

  • io::Write: Trait-ul oricărei destinații de octeți: write_all scrie tot bufferul, flush golește memoria tampon; permite write!.
  • io::BufRead: Trait-ul cititorilor cu buffer: oferă citire pe linii (lines, read_line) pentru fișiere, stdin și octeți din memorie.
  • fs::read: Citește tot conținutul unui fișier ca octeți (Vec<u8>), fără să ceară ca textul să fie UTF-8.
  • File: Un fișier deschis: File::open îl deschide pentru citire, File::create îl creează (sau golește) pentru scriere.