Как прочитать текстовый файл в Rust и прочитать несколько значений в строке

#rust

#Ржавчина

Вопрос:

Итак, в принципе, у меня есть текстовый файл со следующим синтаксисом:

 String int    
String int  
String int
 

У меня есть идея, как прочитать значения, если в строке есть только одна запись, но если их несколько, я не знаю, как это сделать.

В Java я бы сделал что-то простое с while и Scanner, но в Rust я понятия не имею.

Я довольно новичок в Rust, поэтому, пожалуйста, помогите мне.

Заранее спасибо за помощь

Решение
Вот мое модифицированное решение кода @netwave:

 use std::fs;
use std::io::{BufRead, BufReader, Error};

fn main() -> Result<(), Error> {
    let buff_reader = BufReader::new(fs::File::open(file)?);
    for line in buff_reader.lines() {
        let parsed = sscanf::scanf!(line?, "{} {}", String, i32);
        println!("{:?}n", parsed);
    }
    Ok(())
}

 

Комментарии:

1. Пахнет появлением кода 🙂

2. @Netwave да, вы правы 🙂

3. Смотрите std::fs::File и read_to_string функцию, подходящую для чтения всего файла, или вы можете использовать BuffReader в ответе Netwave для чтения одной строки за раз

Ответ №1:

Вы можете использовать BuffRead признак, у которого есть read_line метод. Также вы можете использовать lines .

Для этого самым простым вариантом было бы обернуть File экземпляр с помощью BuffReader :

 use std::fs;
use std::io::{BufRead, BufReader};
...
let buff_reader = BufReader::new(fs::File::open(path)?);
loop {
    let mut buff = String::new();
    buff_reader.read_line(amp;mut buff)?;
    println!("{}", buff);
}
 

std::io::Result {
let f = File::open(«log.txt»)?;
let mut reader = BufReader::new(f);


let mut line = String::new();
let len = reader.read_line(&mut line)?;
println!(«First line is {} bytes long», len);
Ok(())
}amp;edition=2018″ rel=»nofollow noreferrer»>Игровая площадка

Получив каждую строку, вы можете легко использовать sscanf crate для разбора строки на нужные вам типы:

 let parsed = sscanf::scanf!(buff, "{} {}", String, i32);
 

Комментарии:

1. Если вы предпочитаете написать свой собственный макрос для анализа данных вместо использования ящика, вот низкотехнологичная версия, которая по-прежнему довольно универсальна. (игровая площадка не поддерживает ввод-вывод, поэтому я просто дал ему литерал, но он все еще показывает его использование)

2. спасибо за этот простой фрагмент кода, я немного изменил его

Ответ №2:

На основе: https://doc.rust-lang.org/rust-by-example/std_misc/file/read_lines.html

Для data.txt того, чтобы содержать:

 str1 100
str2 200
str3 300
 
 use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;

fn main() {
    // File hosts must exist in current path before this produces output
    if let Ok(lines) = read_lines("./data.txt") {
        // Consumes the iterator, returns an (Optional) String
        for line in lines {
            if let Ok(data) = line {
                let values: Vec<amp;str> = data.split(' ').collect();
                match values.len() {
                  2 => {
                    let strdata = values[0].parse::<String>();
                    let intdata =  values[1].parse::<i32>();
                    println!("Got: {:?} {:?}", strdata, intdata);
                  },
                  _ => panic!("Invalid input line {}", data),
                };
            }
        }
    }
}

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

 

Выводит:

 Got: Ok("str1") Ok(100)
Got: Ok("str2") Ok(200)
Got: Ok("str3") Ok(300)
 

Комментарии:

1. Немного сложный, но правильный ответ

2. хороший момент! не для начинающих, ссылка на игровую площадку от Netwave хороша и проста!

3. Да, его ответ был сокращен с использованием таких вещей, как оператор try ( ? ), что устраняет необходимость в if let s и sscanf кажется достаточно хорошим для выполнения синтаксического анализа.