Запись в файл в Ruby с каждой итерацией цикла - PullRequest
0 голосов
/ 27 апреля 2020

Я имею дело с двумя большими файлами, которые не помещаются в моей оперативной памяти:

  • Я могу sh загрузить две строки каждого, обработать их и записать их.
  • Мне нужно, чтобы это было две строки одновременно из-за природы этих файлов.

Моя программа не пишет строки во время работы, быстро использует мою оперативную память и уничтожается целевой файл создан, но все еще пуст.

Я пробовал $stdout.puts, f.puts, |f| f.write и сброс.

Это дает желаемый результат в небольших файлах, но разделение моих файлов просто не похоже на путь к go.

У меня есть 2 файла и одинаковое количество строк, и оба в следующем формате:

> Line1
Line2

И мне нужно вывести их как

@ Строка 1 из файла 1
Строка 2 из файла 1
+ Строка 1 из файла 2
Строка 2 из файла 2

Вот мой текущий код:

#!/usr/bin/ruby

file1 = File.open(ARGV[0])
file2 = File.open(ARGV[1])
outFile = File.open(ARGV[2], 'a')
i = 1
(file1.each_slice(2)).zip((file2.each_slice(2))).each do |f1l, f2l|
  outFile.write (f1l[0].tr(">", "@")+"\n")
  outFile.write (f1l[1]+"\n")
  outFile.write (f2l[0].tr(">", "+") +"\n")
  outFile.write (f2l[1]+"\n")
  if (i % 100) == 0
    GC.start
  end
  i = i+1
end
file1.close
file2.close
outFile.close

1 Ответ

2 голосов
/ 27 апреля 2020

Давайте использовать IO :: write для создания двух входных файлов.

FNameIn1 = 'in1'
File.write(FNameIn1, "cow\npig\ngoat\nhen\n")
  #=> 17

Мы можем использовать IO :: read для подтверждения того, что было написано.

puts File.read(FNameIn1)
cow
pig
goat
hen

FNameIn2 = 'in2'
File.write(FNameIn2, "12\n34\n56\n78\n")
  #=> 12 
puts File.read(FNameIn2)
12
34
56
78

Далее, используйте File :: open , чтобы открыть два входных файла для чтения и получить дескриптор файла для каждый.

f1 = File.open(FNameIn1)
  #=> #<File:in1> 
f2 = File.open(FNameIn2)
  #=> #<File:in2>

Теперь откройте файл для записи.

FNameOut = 'out'
f = File.open(FNameOut, "w")
  #=> #<File:out>

Предполагая, что два входных файла имеют одинаковое количество строк, в while l oop прочитайте в следующей строке от каждого объедините две строки некоторым образом и запишите полученную строку в выходной файл.

until f1.eof
  line11 = f1.gets.chomp
  line12 = f1.gets.chomp
  line21 = f2.gets.chomp
  line22 = f2.gets.chomp
  f.puts "%s %s, %s %s" % [line11, line21, line12, line22]
end

См. IO # eof , IO # gets и IO # помещает .

Наконец, используйте IO # close , чтобы закрыть файлы.

f1.close
f2.close
f.close

Давайте посмотрим, что FileOut выглядит так.

puts File.read(FNameOut)
cow 12, pig 34
goat 56, hen 78

Вот еще один способ, используя IO :: foreach , который без блока возвращает перечислитель, позволяющий использовать Enumerable # each_slice , как указано в вопросе.

e1 = File.foreach(FNameIn1).each_slice(2)
  #=> #<Enumerator: #<Enumerator: File:foreach("in1")>:each_slice(2)>
e2 = File.foreach(FNameIn2).each_slice(2)
  #=> #<Enumerator: #<Enumerator: File:foreach("in2")>:each_slice(2)> 

File.open(FNameOut, "w") do |f|
  loop do
    line11, line12 = e1.next.map(&:chomp)
    line21, line22 = e2.next.map(&:chomp)
    f.puts "%s %s, %s %s" % [line11, line21, line12, line22]
  end
end

* 10 52 *

puts File.read(FNameOut)
cow 12, pig 34
goat 56, hen 78

Мы можем наблюдать значения, сгенерированные перечислителем

e1 = File.foreach(FNameIn1).each_slice(2)

, многократно выполняя Перечислитель # следующий :

e1.next
  #=> ["cow\n", "pig\n"] 
e1.next
  #=> ["goat\n", "hen\n"] 
e1.next
  #=> StopIteration (iteration reached an end)

Исключение StopIteration, когда оно вызывается, обрабатывается Kernel # l oop путем отключения от l oop (что является одной из причин, по которым loop так полезен) .

Обратите внимание, что при использовании с блоком File::open закрывает файл при выходе из блока.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...