Подтвердить что ты не робот

Редактировать каждую строку в файле в Ruby

Я пытаюсь найти простой способ редактирования каждой строки в файле, и у меня возникли проблемы с пониманием того, как использовать класс File для этого.

Файл, который я хочу изменить, содержит несколько сотен строк с запятыми в каждой строке. Меня интересует только первое значение в каждой строке, и я хочу удалить все значения после первого. Я попытался сделать следующее:

File.open('filename.txt', 'r+') do |file|
  file.each_line { |line| line = line.split(",")[0] }
  file.write
  file.close
end

Что не работает, потому что метод File.write требует, чтобы содержимое было записано в качестве аргумента.

Может ли кто-нибудь просветить меня о том, как я мог бы достичь желаемого эффекта?

4b9b3361

Ответ 1

Одним из лучших решений (и безопаснее) является создание временного файла с помощью TempFile и переместите его в исходное местоположение (используя FileUtils), как только вы закончите:

   require 'fileutils'
   require 'tempfile'

    t_file = Tempfile.new('filename_temp.txt')
    File.open("filename.txt", 'r') do |f|
      f.each_line{|line| t_file.puts line.split(",")[0].to_s }
    end
    t_file.close
    FileUtils.mv(t_file.path, "filename.txt")

Ответ 2

Другой способ изменить файл на месте - использовать переключатель -i

ruby -F"," -i.bak -ane 'puts $F[0]' file

Ответ 3

Обработка файлов с использованием кода существенно отличается от того, что мы делаем, когда мы, например, редактируем файл в текстовом редакторе. Файловые операции, предлагаемые операционными системами, в этом отношении весьма ограничены (из-за многочисленных, частично исторических причин - считать магнитные ленты).

Короче говоря, вы, вероятно, должны создать другой файл и записать в него данные (Mike предоставил код для этого) или загрузить весь файл в памяти (что может быть плохой идеей, если ваш файл огромен) и перезаписать его обработанными данными.

Просто для практики, как вы могли бы фактически редактировать файл на месте. Как вы можете видеть, не самый красивый вид:

File.open('foo', 'r+') do |file|
  write_pos = 0
  file.each do |line|
    word = line.chomp.split(',').first
    read_pos = file.pos
    file.pos = write_pos
    file.puts word
    write_pos = file.pos
    file.pos = read_pos
  end
  file.truncate write_pos
end

Ответ 4

Я думаю, вы неправильно поняли, что это за линия

file.each_line { |line| line = line.split(",")[0].to_s }

действительно делает. Он берет строку, разбивает ее на запятую, берет первое значение, превращает ее в строку (она уже была), присваивает результат блочно-локальной переменной "строка". А потом?
Он переходит к следующей строке, и с предыдущим ничего не делается - все прошло. См. Другие ответы, как исправить это.

Ответ 5

Проблема с принятым ответом заключается в том, что он изменяет права доступа к файлам и права собственности (обратите внимание на это).

Другим подходом является использование внутри редактирования внутри Ruby (не из командной строки):

#!/usr/bin/ruby

def inplace_edit(file, bak, &block)
    old_stdout = $stdout
    argf = ARGF.clone

    argf.argv.replace [file]
    argf.inplace_mode = bak
    argf.each_line do |line|
        yield line
    end
    argf.close

    $stdout = old_stdout
end

inplace_edit 'test.txt', '.bak' do |line|
    line = line.gsub(/search1/,"replace1")
    line = line.gsub(/search2/,"replace2")
    print line unless line.match(/something/)
end

Если вы не хотите создавать резервную копию, измените ".bak" на ".".