Your first problem is a duplicate of this question. TLDR: you need to call by_ref
if you want to be able to reuse reader2
after calling its lines
method (eg. in the next loop iteration).
With that your code will compile but won't work, because once you have processed the first line of the first file you are at the end of the second file, so the second file will appear empty when processing the subsequent lines. You can fix that by rewinding the second file for each line. The minimal set of changes that will make your code work is:
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() {
let filename1 = "file1.txt";
let filename2 = "file2.txt";
// Open the file in read-only mode (ignoring errors).
let file = File::open(filename1).unwrap();
let reader = BufReader::new(file);
let file2 = File::open(filename2).unwrap();
let mut reader2 = BufReader::new(file2);
// Read the file line by line using the lines() iterator from std::io::BufRead.
for line1 in reader.lines() {
let line1 = line1.unwrap(); // Ignore errors.
reader2.seek (SeekFrom::Start (0)).unwrap(); // <-- Add this line
for line2 in reader2.by_ref().lines() { // <-- Use by_ref here
let line2 = line2.unwrap(); // Ignore errors.
if line2 == line1 {
println!("{}",line2)
}
}
}
}
However this will be pretty slow. You can make it much faster by reading one of the files in a HashSet
and checking if each line of the other file is in the set:
use std::collections::HashSet;
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() {
let filename1 = "file1.txt";
let filename2 = "file2.txt";
// Open the file in read-only mode (ignoring errors).
let file = File::open(filename1).unwrap();
let reader = BufReader::new(file);
let file2 = File::open(filename2).unwrap();
let reader2 = BufReader::new(file2);
let lines2 = reader2.lines().collect::<Result<HashSet<_>, _>>().unwrap();
// Read the file line by line using the lines() iterator from std::io::BufRead.
for line1 in reader.lines() {
let line1 = line1.unwrap(); // Ignore errors.
if lines2.contains (&line1) {
println!("{}", line1)
}
}
}
Finally you can also read both files into HashSet
s and print out the intersection:
use std::collections::HashSet;
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() {
let filename1 = "file1.txt";
let filename2 = "file2.txt";
// Open the file in read-only mode (ignoring errors).
let file = File::open(filename1).unwrap();
let reader = BufReader::new(file);
let lines1 = reader.lines().collect::<Result<HashSet<_>, _>>().unwrap();
let file2 = File::open(filename2).unwrap();
let reader2 = BufReader::new(file2);
let lines2 = reader2.lines().collect::<Result<HashSet<_>, _>>().unwrap();
for l in lines1.intersection (&lines2) {
println!("{}", l)
}
}
As a bonus this last solution will remove duplicate lines. OTOH it won't preserve the order of the lines.