【发布时间】:2015-10-21 01:33:03
【问题描述】:
如何删除文本文件中的一个字符而不处理文件中的其余数据?例如,file.txt 有 1234567,我想删除 6,所以 file.txt 包含 123457,而不会将整个文件读入内存。
【问题讨论】:
标签: file text fstream random-access
如何删除文本文件中的一个字符而不处理文件中的其余数据?例如,file.txt 有 1234567,我想删除 6,所以 file.txt 包含 123457,而不会将整个文件读入内存。
【问题讨论】:
标签: file text fstream random-access
这是不可能的。如果不处理文件的剩余后缀以缩小间隙,则无法删除字符。
大多数主流文件系统的底层数据结构不支持对任意范围的字节或单个字节进行恒定时间删除。
这不仅仅是文件系统结构的问题。在不移动任何数据的情况下删除字节会导致文件块和内存页之间的不对齐。这对缓冲、缓存和内存映射有影响。
【讨论】:
File.truncate 'file', File.size('file') - 2。
truncate 和ftruncate 库函数。在 Windows API 中,函数 SetFilePointer 用于查找文件中的某个位置,SetEndOfFile 用于在该位置之后截断文件。
fstream 在标签中,暗示 C++。
如果没有某种方式来索引数据流,您通常无法将文本作为随机访问数据读取。更重要的是,即使您可以更改单个字节而不写入文件的其余部分,您也不能删除一个字节而不写出已删除文本之后的文件其余部分。
由于您没有在原始问题中指定语言,我将向您指出一些允许面向行、面向字符和面向字节的文件操作的 Ruby 方法。这将使您能够将文本视为一系列字符或字节,而不必一次将整个文件放入内存中。
考虑以下Ruby IO methods的区别:
一般来说,只要您有足够的内存,使用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
【讨论】: