Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

read_lines

Наївний підхід

Це може бути розумною першою спробою для першої реалізації початківця для читання рядків із файла.

#![allow(unused)]
fn main() {
use std::fs::read_to_string;

fn read_lines(filename: &str) -> Vec<String> {
    let mut result = Vec::new();

    for line in read_to_string(filename).unwrap().lines() {
        result.push(line.to_string())
    }

    result
}
}

Оскільки метод lines() повертає ітератор по рядках у файлі, ми також можемо виконати map inline і зібрати результати, отримуючи більш стислий і плавний вираз.

#![allow(unused)]
fn main() {
use std::fs::read_to_string;

fn read_lines(filename: &str) -> Vec<String> {
    read_to_string(filename)
        .unwrap()  // panic on possible file-reading errors
        .lines()  // split the string into an iterator of string slices
        .map(String::from)  // make each slice into a string
        .collect()  // gather them together into a vector
}
}

Зверніть увагу, що в обох прикладах вище ми маємо перетворити посилання &str, повернуте з lines(), на тип-власник String, використовуючи відповідно .to_string() і String::from.

Більш ефективний підхід

Тут ми передаємо володіння відкритим File структурам BufReader. BufReader використовує внутрішній буфер, щоб зменшити проміжні виділення.

Ми також оновлюємо read_lines, щоб повертати ітератор замість виділення нових об’єктів String у пам’яті для кожного рядка.

use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;

fn main() {
    // File hosts.txt must exist in the current path
    if let Ok(lines) = read_lines("./hosts.txt") {
        // Consumes the iterator, returns an (Optional) String
        for line in lines.map_while(Result::ok) {
            println!("{}", line);
        }
    }
}

// The output is wrapped in a Result to allow matching on errors.
// Returns an Iterator to the Reader of the lines of the file.
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where P: AsRef<Path>, {
    let file = File::open(filename)?;
    Ok(io::BufReader::new(file).lines())
}

Запуск цієї програми просто виводить рядки окремо.

$ echo -e "127.0.0.1\n192.168.0.1\n" > hosts.txt
$ rustc read_lines.rs && ./read_lines
127.0.0.1
192.168.0.1

(Зверніть увагу, що оскільки File::open очікує як аргумент узагальнений AsRef<Path>, ми визначаємо наш узагальнений метод read_lines() з таким самим узагальненим обмеженням, використовуючи ключове слово where.)

Цей процес є більш ефективним, ніж створення String у пам’яті з усім вмістом файла. Це особливо може спричиняти проблеми з продуктивністю під час роботи з більшими файлами.