Ruby - чтение файла в пакетном режиме
Я читаю файл размером 10 МБ, который содержит некоторые идентификаторы. Я прочитал их в список в рубине. Я обеспокоен тем, что это может вызвать проблемы с памятью в будущем, когда число идентификаторов в файле может увеличиться. Есть ли эффективный способ чтения большого файла в пакетном режиме?
Спасибо
3 ответа
Нет универсального пути.
1) вы можете прочитать файл по частям:
File.open('filename','r') do |f|
chunk = f.read(2048)
...
end
недостаток: вы можете пропустить подстроку, если она будет между кусками, то есть вы ищете "SOME_TEXT", но "SOME_" - это последние 5 байтов 1-го 2048-байтового блока, а "TEXT" - это 4 байта 2-го блока
2) Вы можете читать файл построчно
File.open('filename','r') do |f|
line = f.gets
...
end
недостаток: так будет медленнее, чем в первый раз, в 2,5 раза
С помощью Lazy Enumerators и each_slice вы можете получить лучшее из обоих миров. Вам не нужно беспокоиться о разрезании линий в середине, и вы можете перебирать несколько строк в пакете. batch_size
можно выбрать свободно.
header_lines = 1
batch_size = 2000
File.open("big_file") do |file|
file.lazy.drop(header_lines).each_slice(batch_size) do |lines|
# do something with batch of lines
end
end
Его можно использовать для импорта огромного файла CSV в базу данных:
require 'csv'
batch_size = 2000
File.open("big_data.csv") do |file|
headers = file.first
file.lazy.each_slice(batch_size) do |lines|
csv_rows = CSV.parse(lines.join, write_headers: true, headers: headers)
# do something with 2000 csv rows, e.g. bulk insert them into a database
end
end
Если вас так сильно беспокоит скорость / эффективность памяти, рассматривали ли вы возможность использования оболочки в оболочке и использования
grep
,
awk
,
sed
так далее.? Если бы я знал немного больше о структуре входного файла и о том, что вы пытаетесь извлечь, я мог бы создать для вас команду.