如何替换.txt文件中的单词

时间:2014-11-30 16:26:17

标签: rust

我想打开一个文件,只替换其中的一个单词。除了通过使用新文本创建新文件之外,我似乎无法找到任何方法。

1 个答案:

答案 0 :(得分:9)

文件是一个字节序列。出于性能原因,文件几乎总是占用硬盘驱动器上的一个空间块。从程序员的角度来看,操作连续文件也更容易,因为在这种情况下,文件可以被认为是一个普通的数组;否则应该有一些链表式或类似树的数据结构,在99%的情况下只会使编程更难。因此,可以轻松地附加文件,但在中间插入或删除数据更难。这通常分五步完成(插入;删除非常相似):

  1. 创建一个新的临时文件(或者,如果文件大小适中,则在内存中创建一个缓冲区)
  2. 将插入点之前的所有内容复制到此新文件
  3. 将新数据写入此新文件或
  4. 将插入点后的所有内容复制到新文件
  5. 复制完所有内容后,将移动临时文件以替换原始文件
  6. 替换可能不同长度的单词通常涉及删除或插入。对于大小合适的文件,最简单的方法是将整个源文件读入内存,对其运行替换操作并将结果转储回原始文件。这样,项目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操作,将结果写入临时文件。处理完整个源文件后,临时文件将在其上移动。如果你读取大于单字节的块,你还需要处理你的单词在这些块之间“分裂”的情况。