Вы можете писать в середине файла, но вы должны быть осторожны, чтобы сохранить длину строки, которую вы перезаписываете, то же самое, в противном случае вы перезаписываете часть следующего текста.Я привожу здесь пример, используя File.seek, IO :: SEEK_CUR дает текущую позицию указателя файла, в конце строки, которая только что прочитана, +1 для символа CR в конце строки.
look_for = "bbb"
replace_with = "xxxxx"
File.open(DATA, 'r+') do |file|
file.each_line do |line|
if (line[look_for])
file.seek(-(line.length + 1), IO::SEEK_CUR)
file.write line.gsub(look_for, replace_with)
end
end
end
__END__
aaabbb
bbbcccddd
dddeee
eee
После выполнения, в конце сценария у вас теперь есть следующее, а не то, что вы имели в виду, я предполагаю.
aaaxxxxx
bcccddd
dddeee
eee
Учитывая это, скорость, с помощью которой этоТехника намного лучше, чем классический метод «чтение и запись в новый файл».Смотрите эти тесты в файле с музыкальными данными размером 1,7 ГБ.Для классического подхода я использовал технику Уэйна.Тест выполняется с помощью метода .bmbm, поэтому кэширование файла не играет большой роли.Тесты выполняются с помощью MRI Ruby 2.3.0 в Windows 7. Строки были эффективно заменены, я проверил оба метода.
require 'benchmark'
require 'tempfile'
require 'fileutils'
look_for = "Melissa Etheridge"
replace_with = "Malissa Etheridge"
very_big_file = 'D:\Documents\muziekinfo\all.txt'.gsub('\\','/')
def replace_with file_path, look_for, replace_with
File.open(file_path, 'r+') do |file|
file.each_line do |line|
if (line[look_for])
file.seek(-(line.length + 1), IO::SEEK_CUR)
file.write line.gsub(look_for, replace_with)
end
end
end
end
def replace_with_classic path, look_for, replace_with
temp_file = Tempfile.new('foo')
File.foreach(path) do |line|
if (line[look_for])
temp_file.write line.gsub(look_for, replace_with)
else
temp_file.write line
end
end
temp_file.close
FileUtils.mv(temp_file.path, path)
ensure
temp_file.close
temp_file.unlink
end
Benchmark.bmbm do |x|
x.report("adapt ") { 1.times {replace_with very_big_file, look_for, replace_with}}
x.report("restore ") { 1.times {replace_with very_big_file, replace_with, look_for}}
x.report("classic adapt ") { 1.times {replace_with_classic very_big_file, look_for, replace_with}}
x.report("classic restore") { 1.times {replace_with_classic very_big_file, replace_with, look_for}}
end
, что дало
Rehearsal ---------------------------------------------------
adapt 6.989000 0.811000 7.800000 ( 7.800598)
restore 7.192000 0.562000 7.754000 ( 7.774481)
classic adapt 14.320000 9.438000 23.758000 ( 32.507433)
classic restore 14.259000 9.469000 23.728000 ( 34.128093)
----------------------------------------- total: 63.040000sec
user system total real
adapt 7.114000 0.718000 7.832000 ( 8.639864)
restore 6.942000 0.858000 7.800000 ( 8.117839)
classic adapt 14.430000 9.485000 23.915000 ( 32.195298)
classic restore 14.695000 9.360000 24.055000 ( 33.709054)
Таким образом, замена in_file была 4раз быстрее.