#ruby
Вопрос:
У меня есть XML-файл размером 30 МБ, который вначале содержит некоторую тарабарщину, и поэтому, как правило, мне приходится удалять его, чтобы Nokogiri мог правильно проанализировать XML-документ.
Вот что у меня сейчас есть:
contents = File.open(file_path).read
if contents[0..123].include? 'authenticate_response'
fixed_contents = File.open(file_path).read[123..-1]
File.open(file_path, 'w') { |f| f.write(fixed_contents) }
end
Однако на самом деле это приводит к тому, что скрипт ruby дважды открывает большой XML-файл. Один раз, чтобы прочитать первые 123 символа, а в другой раз, чтобы прочитать все, кроме первых 123 символов.
Чтобы решить первую проблему, я смог выполнить это:
contents = File.open(file_path).read(123)
Однако теперь мне нужно удалить эти символы из файла, не читая весь файл целиком. Как я могу «обрезать» начало этого файла, не открывая его целиком в памяти?
Комментарии:
1. «заменить» сильно отличается от «удалить». Вы не можете сделать последнее, не прочитав весь файл целиком.
Ответ №1:
Вы можете открыть файл один раз, затем прочитать и проверить «мусор» и, наконец, передать открытый файл непосредственно в nokogiri для анализа. Таким образом, вам нужно прочитать файл только один раз, и вам вообще не нужно его записывать.
File.open(file_path) do |xml_file|
if xml_file.read(123).include? 'authenticate_response'
# header found, nothing to do
else
# no header found. We rewind and let nokogiri parse the whole file
xml_file.rewind
end
xml = Nokogiri::XML.parse(xml_file)
# Now to whatever you want with the parsed XML document
end
Пожалуйста , обратитесь к документации IO#read
IO#rewind
и Nokigiri::XML::Document.parse
для получения подробной информации об этих методах.
Комментарии:
1. Вам следует подумать о добавлении
begin ... ensure; xml_file.close; end
.2. Я обновил ответ, чтобы использовать блочный вариант
File.open
. Однако даже без этого файл будет неявно закрыт при следующей сборке мусора.3. @HolgerJust что привело бы вас к мысли, что это будет GCed?
4. @enginersmnky: Потому что в первоначальной версии моего ответа файловый объект был назначен локальной переменной, которая выйдет за рамки области действия, как только выполнение вернется из метода, в котором находится код. После этого файловый объект будет собран как мусор, а файл закрыт.
5. @HolgerJust Я думаю, что это чрезвычайно зависит, так как операция и ваш первоначальный ответ технически работают в глобальной области
main
, поэтому этот файл будет оставаться открытым до тех пор, пока сама программа не завершится.