我想打开一个文件,只替换其中的一个单词。除了通过使用新文本创建新文件之外,我似乎无法找到任何方法。
答案 0 :(得分:9)
文件是一个字节序列。出于性能原因,文件几乎总是占用硬盘驱动器上的一个空间块。从程序员的角度来看,操作连续文件也更容易,因为在这种情况下,文件可以被认为是一个普通的数组;否则应该有一些链表式或类似树的数据结构,在99%的情况下只会使编程更难。因此,可以轻松地附加文件,但在中间插入或删除数据更难。这通常分五步完成(插入;删除非常相似):
替换可能不同长度的单词通常涉及删除或插入。对于大小合适的文件,最简单的方法是将整个源文件读入内存,对其运行替换操作并将结果转储回原始文件。这样,项目2-4将由库代码自动为您完成字符串操作。这是一个示例程序(它从命令行参数中获取源词,替换字和文件路径):
use std::env;
use std::fs::File;
use std::io::{self, Read, Write};
use std::path::Path;
fn main() {
// Handle errors
run().unwrap();
}
fn run() -> Result<(), io::Error> {
// Extract words and file path from the command line args
let args: Vec<String> = env::args().skip(1).collect();
if args.len() != 3 {
println!("Wrong number of arguments");
return Ok(());
}
let word_from = &args[0];
// If the source word is empty then there is nothing to replace
if word_from.is_empty() { return Ok(()); }
let word_to = &args[1];
let file_name = &args[2];
let file_path = Path::new(&file_name);
// Open and read the file entirely
let mut src = File::open(&file_path)?;
let mut data = String::new();
src.read_to_string(&mut data)?;
drop(src); // Close the file early
// Run the replace operation in memory
let new_data = data.replace(&*word_from, &*word_to);
// Recreate the file and dump the processed contents to it
let mut dst = File::create(&file_path)?;
dst.write(new_data.as_bytes())?;
println!("done");
Ok(())
}
请注意,创建临时文件仍然是一个好主意,因为将大块数据写入文件不是原子操作,而重命名文件通常是。因此,如果出现问题并且您不使用临时文件,您的源文件可能会损坏。如果您确实使用了临时文件,那么源文件将被完全替换或不被替换。
如果您的文件很大(即几千兆字节或更大),则流式替换可能是一个好主意。在这种情况下,您需要以块的形式读取文件(长度减少到1个字节,这可能会更容易)并在这些块中运行replace操作,将结果写入临时文件。处理完整个源文件后,临时文件将在其上移动。如果你读取大于单字节的块,你还需要处理你的单词在这些块之间“分裂”的情况。