Ваша проблема в том, что вы открываете файл один раз, читаете весь файл и затем предполагаете, что он будет сброшен волшебным образом.
A File
имеет позицию "указатель", чтобы знать, какой байт читать следующим,После того, как вы прочитали один байт, эта позиция будет увеличена на единицу, поэтому при следующем вызове чтения будет прочитан следующий, а не тот же байт.
Вы можете изменить эту позицию с помощью File::seek
между вашими звонками на count_lines
, count_bytes
и count_words
.
use std::io::{Seek, SeekFrom};
fn main() {
let arg = &std::env::args()
.nth(1)
.expect("No file operand found")
.to_owned();
let mut file = File::open(arg).expect("Unable to open file for reading");
let lines = count_lines(&file);
print!("{} ", lines);
file.seek(SeekFrom::Start(0)).expect("Seek failed");
let bytes = count_bytes(&file);
println!("{}", bytes);
file.seek(SeekFrom::Start(0)).expect("Seek failed");
let words = count_words(&file);
print!("{} ", words);
}
Для дальнейшего обращения к вашему коду он не считается очень "ржавым".Ваш ручной подсчет может быть упрощен с помощью Iterator::count
.
fn count_lines(file: &File) -> u32 {
BufReader::new(file).lines().count() as u32
}
fn count_bytes(file: &File) -> u32 {
BufReader::new(file).bytes().count() as u32
}
Причина, по которой ваша функция count_words
"зависает", заключается в том, что вы игнорируете количество прочитанных байтов,Когда read_until
достигает EOF (конец файла), возвращается 0
как сумма.Вы должны ввести условие останова, например,
fn count_words(file: &File) -> u32 {
let mut count: u32 = 0;
let mut buf: Vec<u8> = Vec::new();
let mut reader = BufReader::new(file);
while let Ok(amount) = reader.read_until(b' ', &mut buf) {
if amount == 0 {
break
}
count += 1;
}
count
}
Обратите внимание, что эта реализация на самом деле не верна, потому что "hello "
(два пробела в конце) даст вам 2
вместо 1
, но это решать вам. добавьте несколько тестов , чтобы убедиться, что все работает правильно.