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

String 如何逐行读取文件,消除重复项,然后写回同一个文件?,string,file,rust,duplicate-removal,String,File,Rust,Duplicate Removal,我想读取一个文件,消除所有重复的内容,然后将其余内容写回文件中,就像一个重复的清洁器一样。 Vec,因为普通数组的大小是固定的,但my.txt是灵活的(我这样做对吗?) 读取,Vec中的行+删除副本: 缺少对文件的回写 use std::io; fn main() { let path = Path::new("test.txt"); let mut file = io::BufferedReader::new(io::File::open(&path, R));

我想读取一个文件,消除所有重复的内容,然后将其余内容写回文件中,就像一个重复的清洁器一样。 Vec,因为普通数组的大小是固定的,但my.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());
    }
}
使用std::io;
fn main(){
让path=path::new(“test.txt”);
让mut file=io::BufferedReader::new(io::file::open(&path,R));
让mut行:Vec=file.lines().map(|x | x.unwrap()).collect();
//重复数据消除()删除所有重复项,如果排序()在
line.sort();
行。重复数据消除();
对于e-in-line.iter(){
打印!(“{}”,例如as_slice());
}
}
读+写文件(未经测试,但我想应该可以工作)。 由于没有BufferedReader(或者我做错了其他事情,这也是一个很好的机会),Vec的行丢失了

使用std::io;
fn main(){
让path=path::new(“test.txt”);
让mut file=match io::file::open_模式(&path,io::open,io::ReadWrite){
Ok(f)=>f,
Err(e)=>panic!(“文件错误:{}”,e),
};  
让mut行:Vec=file.lines().map(|x | x.unwrap()).collect();
line.sort();
//重复数据消除()删除所有重复项,如果排序()在
行。重复数据消除();
对于e-in-line.iter(){
写入(“{}”,e);
}
} 

所以。。。。我怎样才能把这两个结合起来呢?:)

最终,您将遇到一个问题:您正试图写入正在读取的同一个文件。在这种情况下,它是安全的,因为您将读取整个文件,因此在读取之后不需要它。但是,如果您确实尝试写入文件,您会看到打开文件进行读取不允许写入!下面是执行此操作的代码:

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

fn main() {
    let mut file = File::open("test.txt").expect("file error");
    let reader = BufReader::new(&mut file);

    let mut lines: Vec<_> = reader
        .lines()
        .map(|l| l.expect("Couldn't read a line"))
        .collect();

    lines.sort();
    lines.dedup();

    for line in lines {
        file.write_all(line.as_bytes())
            .expect("Couldn't write to file");
    }
}
您可以打开文件进行读写操作:

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

fn main() {
    let mut file = OpenOptions::new()
        .read(true)
        .write(true)
        .open("test.txt")
        .expect("file error");

    // Remaining code unchanged
}
但是你会看到(a)输出被追加,(b)所有新行在新行中丢失,因为
BufRead
没有包含它们

我们可以将文件指针重置回起始位置,但随后可能会在末尾留下尾随内容(重复数据消除可能写入的字节数少于读取的字节数)。只需重新打开文件进行写入就更容易了,这将截断文件。另外,让我们使用一套数据结构来为我们执行重复数据消除

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

fn main() {
    let file = File::open("test.txt").expect("file error");
    let reader = BufReader::new(file);

    let lines: BTreeSet<_> = reader
        .lines()
        .map(|l| l.expect("Couldn't read a line"))
        .collect();

    let mut file = File::create("test.txt").expect("file error");

    for line in lines {
        file.write_all(line.as_bytes())
            .expect("Couldn't write to file");

        file.write_all(b"\n").expect("Couldn't write to file");
    }
}
效率较低但较短的解决方案是将整个文件作为一个字符串读取,并使用
str::lines

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

fn main() {
    let contents = fs::read_to_string("test.txt").expect("can't read");
    let lines: BTreeSet<_> = contents.lines().collect();

    let mut file = File::open("test.txt").expect("can't create");
    for line in lines {
        writeln!(file, "{}", line).expect("can't write");
    }
}
使用std::{
集合::b树集,
fs::{self,File},
io::写,
};
fn main(){
让contents=fs::读取到字符串(“test.txt”).expect(“无法读取”);
let line:BTreeSet=contents.lines().collect();
让mut file=file::open(“test.txt”).expect(“无法创建”);
排队{
writeln!(文件“{}”,行)。预期(“无法写入”);
}
}
另见:


您是对算法感兴趣,还是对如何实现这一点感兴趣,或者问题是关于生锈的?两者都有;)。我想提高我的抗锈能力和我的常规编程技能,因此我尝试了一些现实生活中的脚本以获得乐趣。使用
BTreeSet
而不是
HashSet
(和
。into iter()
而不是
。drain()
)将对行进行排序。
% cat test.txt
a
a
b
a
a
b
a
b

% cargo run
% cat test.txt
a
b
use std::{
    collections::BTreeSet,
    fs::{self, File},
    io::Write,
};

fn main() {
    let contents = fs::read_to_string("test.txt").expect("can't read");
    let lines: BTreeSet<_> = contents.lines().collect();

    let mut file = File::open("test.txt").expect("can't create");
    for line in lines {
        writeln!(file, "{}", line).expect("can't write");
    }
}