【问题标题】:How can I prepend a line to the beginning of a file?如何在文件开头添加一行?
【发布时间】:2017-04-16 19:23:47
【问题描述】:

我正在尝试在文本文件的开头添加新行。我首先使用append 打开文件,但这仅允许我使用write_all 写入文件末尾,至少这是我得到的结果。如果我正确阅读了文档,这是设计使然。

我尝试过使用seek,但这并没有解决问题。

这是我目前拥有的:

let mut file = OpenOptions::new().append(true).open(&file_path).unwrap();
file.seek(SeekFrom::Start(0));
file.write_all(b"Cool days\n");

如果我用write 打开文件,我最终会覆盖数据而不是添加。使用 Rust 完成此任务的合适方法是什么?

【问题讨论】:

  • 如果您在文件的开头添加一行,则需要移动文件的所有剩余内容以适应它。在任何编程语言中都没有办法解决这个问题。见this example in C#

标签: file io rust


【解决方案1】:

您不能直接在任何编程语言中执行此操作。在C#PythonNodeJsPHPBashC 中查看有关同一主题的其他一些问题。

有几种不同的权衡解决方案:

  1. 将整个文件复制到内存中,写入你想要的数据,然后写入文件的其余部分。如果文件很大,这可能是一个糟糕的解决方案,因为它会使用大量内存,但可能适合小文件,因为它很容易实现。

  2. 使用与要添加的文本大小相同的缓冲区。一次将文件的块复制到内存中,然后用前一个块覆盖它。通过这种方式,您可以将文件的内容与开始的新文本一起打乱。这可能比其他方法慢,但不需要大的内存分配。当进程无权删除文件时,它也可能是最佳选择。但要小心:如果进程被中断,这种方法可能会使文件处于损坏状态。

  3. 将新数据写入临时文件,然后附加原始文件的内容。然后删除原始文件并重命名临时文件。这是一个很好的解决方案,因为它将繁重的工作委托给操作系统,并且备份了原始数据,因此即使进程中断也不会损坏。

从 Stack Overflow 上的搜索来看,第三种解决方案似乎是其他语言最流行的答案,例如in Bash。这可能是因为它速度快、安全且通常只需几行代码即可实现。

快速的 Rust 版本如下所示:

extern crate mktemp;
use mktemp::Temp;
use std::{fs, io, io::Write, fs::File, path::Path};

fn prepend_file<P: AsRef<Path>>(data: &[u8], file_path: &P) -> io::Result<()> {
    // Create a temporary file 
    let mut tmp_path = Temp::new_file()?;
    // Stop the temp file being automatically deleted when the variable
    // is dropped, by releasing it.
    tmp_path.release();
    // Open temp file for writing
    let mut tmp = File::create(&tmp_path)?;
    // Open source file for reading
    let mut src = File::open(&file_path)?;
    // Write the data to prepend
    tmp.write_all(&data)?;
    // Copy the rest of the source file
    io::copy(&mut src, &mut tmp)?;
    fs::remove_file(&file_path)?;
    fs::rename(&tmp_path, &file_path)?;
    Ok(())
}

用法:

fn main() -> io::Result<()> {
    let file_path = Path::new("file.txt");
    let data = "Data to add to the beginning of the file\n";
    prepend_file(data.as_bytes(), &file_path)?;
    Ok(())
}

【讨论】:

  • 谢谢,这回答了我的问题。我在想像这样的解决方案,但尽管对我自己来说,这感觉就像重新发明轮子,但显然这个轮子确实需要再次制造。顺便说一句,这将是一个很棒的库。
猜你喜欢
  • 2011-02-26
  • 2017-09-11
  • 1970-01-01
  • 2022-01-04
  • 2017-08-17
  • 1970-01-01
  • 1970-01-01
  • 2011-04-15
  • 2013-12-03
相关资源
最近更新 更多