【问题标题】:How do I delete a character in a text file without manipulating the rest of the data in the file?如何在不操作文件中其余数据的情况下删除文本文件中的字符?
【发布时间】:2015-10-21 01:33:03
【问题描述】:

如何删除文本文件中的一个字符而不处理文件中的其余数据?例如,file.txt1234567,我想删除 6,所以 file.txt 包含 123457,而不会将整个文件读入内存。

【问题讨论】:

    标签: file text fstream random-access


    【解决方案1】:

    这是不可能的。如果不处理文件的剩余后缀以缩小间隙,则无法删除字符。

    大多数主流文件系统的底层数据结构不支持对任意范围的字节或单个字节进行恒定时间删除。

    这不仅仅是文件系统结构的问题。在不移动任何数据的情况下删除字节会导致文件块和内存页之间的不对齐。这对缓冲、缓存和内存映射有影响。

    【讨论】:

    • 有没有办法只删除最后一个字符?
    • @Need_Help 在大多数情况下,这不会真正满足您的需求,但您当然可以截断文件。例如,要删除最后一个字符加上尾随换行符:File.truncate 'file', File.size('file') - 2
    • @Need_Help 可能有。主流操作系统有办法将文件截断为给定长度。 POSIX 系统具有truncateftruncate 库函数。在 Windows API 中,函数 SetFilePointer 用于查找文件中的某个位置,SetEndOfFile 用于在该位置之后截断文件。
    • @CodeGnome 不确定您在那里使用的语言;唯一的线索是 fstream 在标签中,暗示 C++。
    • @Kaz 我的示例使用 Ruby。我对使用 OP 玩“猜猜我的语言/实现”没有兴趣。关于截断的观点通常在任何现代语言中都是有效的,但我同意我应该提到我的评论示例的语言,以防有人在没有阅读页面其余部分的上下文的情况下深层链接到该评论。
    【解决方案2】:

    问题

    如果没有某种方式来索引数据流,您通常无法将文本作为随机访问数据读取。更重要的是,即使您可以更改单个字节而不写入文件的其余部分,您也不能删除一个字节而不写出已删除文本之后的文件其余部分。

    由于您没有在原始问题中指定语言,我将向您指出一些允许面向行、面向字符和面向字节的文件操作的 Ruby 方法。这将使您能够将文本视为一系列字符或字节,而不必一次将整个文件放入内存中。

    考虑以下Ruby IO methods的区别:

    • IO#read
    • IO#readline
    • IO#readlines
    • IO#readbyte
    • IO#readchar

    一些实用的解决方案

    最简单的解决方案:优化速度而不是内存

    一般来说,只要您有足够的内存,使用File#read 将整个文件转换为单个字符串或使用File#readlines 创建一个多行数组将是最快的,但内存需求会随着输入文件大小的增长而增长.简而言之,您试图避免文件大小无限的问题,相当于:

    File.read('file') do |f|
      f.delete '6'
    end
    

    除非您对磁盘抖动或内存受限(例如在嵌入式系统中)有合理的预期,否则执行除 slurping 文件之外的其他操作可能是过早的优化。您的里程可能会有所不同。

    内存受限系统的潜在解决方案

    假设它们不是过早的优化,您当然可以将以下方法应用于几乎任何语言。为了便于阅读和实验,我在这里用 Ruby 呈现它们。

    面向线的方法

    使用File#readline 处理多行输入且内存开销很小(当然,假设您的文件有换行符)的一种方法。例如:

    old_file = File.new 'file'
    new_file = File.new 'file.new', 'w'
    
    # Delete the string character '6' from each line of input.
    while line = old_file.readline do
      new_file.puts line.delete '6'
    end 
    

    面向字符的方法

    一种更加节省内存的面向字符的方法可能使用File#readchar。例如:

    old_file = File.new 'file'
    new_file = File.new 'file.new', 'w'
    
    # Write each character to the new file unless the character is "6".
    while char = old_file.readchar do
      new_file.print(char) unless char == '6'
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多