Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access the BufReader twice?

Trying to access the variable sentences for a second time causes value used here after move, I want to understand how to store the total without causing this problem.

I tried to copy the iterator but I can't find a way to make it work or how is the correct way to do it.

extern crate regex;

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

fn main() {
    let sentences_path = Path::new("csv/testSentences.csv");
    let sentences = BufReader::new(File::open(&sentences_path).unwrap());

    let total = sentences.lines().count();

    for (index, sentence) in sentences.lines().enumerate() {
        let line = sentence.unwrap();
        println!("Processed {} of {}, {}", index, total, line);
    }

    println!("Total {}", total);
}
like image 296
Daniel Doblado Avatar asked Jun 16 '19 15:06

Daniel Doblado


2 Answers

You can not access the value if the ownership is moved previously. However you can inspect over your lines with inspect without changing the inner lines but only updating the count.

After you find out the count by iterating the Lines, you can iterate it again and do the logic as you wish.

The main reason why you are getting this compiler error is: count function consumes the Lines you use and you can not access your variable again since it is already consumed.

Here is the solution:

use std::fs::File;
use std::io::{BufRead, BufReader, Write};

fn main() {
    let path = "lines.txt";

    let mut output = File::create(path).unwrap();
    write!(output, "Rust\nšŸ’–\nFun").unwrap();

    let input = File::open(path).unwrap();
    let buffered = BufReader::new(input);

    let lines: Vec<_> = buffered.lines().collect();
    let total = lines.len();

    for (index, sentence) in lines.into_iter().enumerate() {
        let line = sentence.unwrap();
        println!("Processed {} of {}, {}", index, total, line);
    }

    println!("Total {}", total);
}

Playground

With this way, you do not need to read the file twice. You read the file, put it into memory then only iterate it twice.

like image 118
Akiner Alkan Avatar answered Sep 19 '22 16:09

Akiner Alkan


You can't. You need to read the file twice. First to count total lines. And second to process each line. So you need two BufReader:

extern crate regex;                                                                                                     

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

fn get_file_reader(path: &Path) -> impl BufRead {
    BufReader::new(File::open(path).unwrap())
}

fn main() {
    let sentences_path = Path::new("csv/testSentences.csv");
    let sentences = get_file_reader(&sentences_path);

    let total = get_file_reader(&sentences_path).lines().count();

    for (index, sentence) in sentences.lines().enumerate() {
        let line = sentence.unwrap();
        println!("Processed {} of {}, {}", index, total, line);
    }

    println!("Total {}", total);
}
like image 20
antage Avatar answered Sep 19 '22 16:09

antage