I have a build error and tried some suggestions online but they did not work, I am trying to add a progress bar to my code, the code works perfectly well without the progress bar. Any help please ?
use std::fs::File;
use indicatif::{ProgressBar, ProgressStyle};
use std::io::{BufRead, BufReader, Write};
use bip39::Mnemonic;
fn main() {
let input_file = File::open("input.txt").expect("Failed to open input file");
let reader = BufReader::new(input_file);
let output_file = File::create("output.txt").expect("Failed to create output file");
let mut writer = std::io::BufWriter::new(output_file);
let num_lines = reader.lines().count();
let pb = ProgressBar::new(num_lines as u64);
pb.set_style(ProgressStyle::default_bar()
.template("[{elapsed_precise}] {bar:100.cyan/blue} {pos}/{len} ({percent}%)").expect("Failed to create progress bar")
.progress_chars("##-"));
for line in reader.lines() {
if let Ok(mnemonic_str) = line {
let valid = Mnemonic::parse_normalized(&mnemonic_str);
if valid.is_ok() {
writeln!(writer, "{}", mnemonic_str).expect("Failed to write to output file");
}
pb.inc(1);
}
}
pb.finish_with_message("Validation completed");
println!("Valid ones have been written to output.txt");
}
The error I get
error[E0382]: use of moved value: `reader`
--> src\main.rs:19:17
|
8 | let reader = BufReader::new(input_file);
| ------ move occurs because `reader` has type `BufReader<File>`, which does not implement the `Copy` trait
...
13 | let num_lines = reader.lines().count();
| ------- `reader` moved due to this method call
...
19 | for line in reader.lines() {
| ^^^^^^ value used here after move
|
note: `lines` takes ownership of the receiver `self`, which moves `reader`
--> /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\std\src\io\mod.rs:2554:14
For more information about this error, try `rustc --explain E0382`.
error: could not compile `project` (bin "project") due to 1 previous error
warning: variable does not need to be mutable
--> src\main.rs:13:9
|
13 | let mut lines = reader.lines();
| ----^^^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
error[E0382]: use of moved value: `lines`
--> src\main.rs:20:17
|
13 | let mut lines = reader.lines();
| --------- move occurs because `lines` has type `std::io::Lines<BufReader<File>>`, which does not implement the `Copy` trait
14 | let num_lines = lines.count();
| ------- `lines` moved due to this method call
...
20 | for line in lines {
| ^^^^^ value used here after move
|
note: `count` takes ownership of the receiver `self`, which moves `lines`
--> /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\iter\traits\iterator.rs:229:14
Note that this will have to read the whole file, which is probably not what you want.
I would use std::fs::metadata (or the unstable Seek::stream_len) to know the length in bytes of the file and then increment the progress bar by the number of bytes in line (note though this is slightly inaccurate since newline characters won't be counted).
If you insist in reading the whole file to know the number of lines you can use reader.by_ref().lines().count() instead of reader.lines().count(), which won't consume reader. Remember to reset reader by using Seek::unwind, or when you do reader.lines() for the second time it read nothing.
tqdm also doesn't properly show a progress bar if the iterator length is not known ahead of time, like it happens for an iterator of file lines.
For example this is the normal output of tqdm on an iterator with a known length (I've showed all the lines and also added some delay so that none is skipped):
This is the output when the iterator has no known length, notice how there's no progress bar. To keep the example on topic I used an iterator over file lines, just like you were trying to do in your rust code:
@jofas , @SkiFire13 .... Thank you all for your help, i found a fix.
I read the lines again on top of the for-loop and defined reader again and it worked like a charm.
I will update my code in a moment.
use std::fs::File;
use indicatif::{ProgressBar, ProgressStyle};
use std::io::{BufRead, BufReader, Write};
use bip39::Mnemonic;
fn main() {
let input_file = File::open("gain1.txt").expect("Failed to open input file");
let reader = BufReader::new(input_file);
let output_file = File::create("checksum.txt").expect("Failed to create output file");
let mut writer = std::io::BufWriter::new(output_file);
let num_lines = reader.lines().count();
let pb = ProgressBar::new(num_lines as u64);
pb.set_style(ProgressStyle::default_bar()
.template("[{elapsed_precise}] {bar:100.cyan/blue} {pos}/{len} ({percent}%)").expect("Failed to create progress bar")
.progress_chars("##-"));
let input_file = File::open("gain1.txt").expect("Failed to open input file");
let reader = BufReader::new(input_file);
for line in reader.lines() {
if let Ok(mnemonic_str) = line {
let valid = Mnemonic::parse_normalized(&mnemonic_str);
if valid.is_ok() {
writeln!(writer, "{}", mnemonic_str).expect("Failed to write to output file");
}
pb.inc(1);
}
}
pb.finish_with_message("Validation completed");
println!("Valid ones have been written to output.txt");
}
I found out that the progress bar slowed down my code, without the progress bar it took 3 minutes to iterate over a file, with the progress bar, it took 3 minutes 30 seconds to iterate over the same file.