Редактировать каждую строку в файле в Ruby - PullRequest
16 голосов
/ 28 марта 2011

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

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

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

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

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

Ответы [ 5 ]

23 голосов
/ 28 марта 2011

Одним из лучших решений (и наиболее безопасных) является создание временного файла с помощью 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")
11 голосов
/ 28 марта 2011

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

ruby -F"," -i.bak -ane 'puts $F[0]' file
5 голосов
/ 28 марта 2011

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

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

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

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 голосов
/ 28 марта 2011

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

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

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

2 голосов
/ 10 января 2013

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

Другой подход заключается в использовании редактирования на месте внутри 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' на ''.

...