如何逐行读取文件,消除重复项,然后写回同一文件?

时间:2015-01-10 00:07:35

标签: string file rust duplicate-removal

我想读取一个文件,删除所有重复项并将其余部分写回文件 - 就像一个重复的清理器。 Vec因为普通数组的大小固定但我的.txt很灵活(我这样做了吗?)。

阅读,Vec中的行+删除重复项: 缺少回写文件。

use std::io;

fn main() {
    let path = Path::new("test.txt");
    let mut file = io::BufferedReader::new(io::File::open(&path, R));

    let mut lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();
    // dedup() deletes all duplicates if sort() before
    lines.sort();
    lines.dedup();

    for e in lines.iter() {
        print!("{}", e.as_slice());
    }
}

读取+写入文件(未经测试但应该可以工作)。 缺少Vec的行,因为它似乎没有BufferedReader工作(或者我做了别的错误,也是一个很好的机会)。

use std::io;

fn main() {
    let path = Path::new("test.txt");
    let mut file = match io::File::open_mode(&path, io::Open, io::ReadWrite) {
        Ok(f) => f,
        Err(e) => panic!("file error: {}", e),
    };  
    let mut lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();
    lines.sort();
    // dedup() deletes all duplicates if sort() before
    lines.dedup();

    for e in lines.iter() {
        file.write("{}", e);
    }
} 

那么......我怎么把这两个人放在一起? :)

1 个答案:

答案 0 :(得分:2)

最终,您将遇到一个问题:您正在尝试写入您正在阅读的同一文件。在这个的情况下,它是安全的,因为您将要阅读整个文件,因此您之后就不需要它了。但是,如果确实尝试写入文件,那么实际上你最后会写它!这是执行此操作的代码:

use std::io;

fn main() {
    let path = Path::new("test.txt");
    let file = match io::File::open_mode(&path, io::Open, io::ReadWrite) {
        Ok(f) => f,
        Err(e) => panic!("file error: {}", e),
    };
    let mut reader = io::BufferedReader::new(file);

    let mut lines: Vec<String> = reader.lines().map(|x| x.unwrap()).collect();
    lines.sort();
    lines.dedup();

    let mut file = reader.into_inner();

    for line in lines.iter() {
        file.write_str(line.as_slice());
    }
}

密钥是对into_inner的调用,它返回原始文件。这是输出:

$ cat test.txt
a
a
b
a
$ ./dedup
$ cat test.txt
a
a
b
a
a
b

您可以将文件指针重置回到开头,但是您可能会在结尾处留下尾随的东西(重复数据删除可能比写入更少写入字节)。重新打开文件进行写入会更容易,这将截断文件。另外,让我们使用设置数据结构为我们执行重复数据删除!

use std::io;
use std::collections::HashSet;

fn read(path: &Path) -> HashSet<String> {
    let file = match io::File::open(path) {
        Ok(f) => f,
        Err(e) => panic!("file error: {}", e),
    };

    let mut reader = io::BufferedReader::new(file);

    reader.lines().map(|x| x.unwrap()).collect()
}

fn write(path: &Path, mut lines: HashSet<String>) {
    let mut file = match io::File::open_mode(path, io::Truncate, io::Write) {
        Ok(f) => f,
        Err(e) => panic!("file error: {}", e),
    };

    for line in lines.drain() {
        file.write_str(line.as_slice());
    }
}

fn main() {
    let path = Path::new("test.txt");
    let lines = read(&path);
    write(&path, lines);
}

输出:

$ cat test.txt
a
a
b
a
a
b
a
b
$ ./dedup
$ cat test.txt
b
a

Rust 1.0

use std::io::{self,BufRead,Write};
use std::fs::File;
use std::collections::HashSet;

fn read(path: &str) -> HashSet<String> {
    let file = File::open(path).unwrap();
    let reader = io::BufReader::new(file);
    reader.lines().map(|x| x.unwrap()).collect()
}

fn write(path: &str, lines: HashSet<String>) {
    let mut file = File::create(path).unwrap();

    for line in lines {
        writeln!(file, "{}", line).unwrap();
    }
}

fn main() {
    let path = "test.txt";
    let lines = read(path);
    write(path, lines);
}