FasterCSV: Проверьте, является ли файл недействительным, прежде чем принимать его - есть ли более простой способ? - PullRequest
3 голосов
/ 10 мая 2011

Я использую FasterCSV в приложении Ruby on Rails, и в настоящее время он выдает исключение, если файл недействителен.

Я просмотрел FasterCSV doc , и кажется, что если я использую FasterCSV :: parse с блоком, он будет читать файл по одной строке за раз , не выделяя слишком много памяти. В случае ошибки в файле будет выдано исключение FasterCSV :: MalformedCSV .

Я реализовал собственное решение, но я не уверен, что оно наилучшее из возможных (см. Мой ответ ниже). Мне было бы интересно узнать альтернативы

Ответы [ 3 ]

1 голос
/ 11 мая 2011

Это мое текущее решение.Мне действительно интересно знать улучшения / альтернативы.

# /lib/fastercsv_is_valid.rb

class FasterCSV

  def self.is_valid?(file, options = {})
    begin
      FasterCSV.parse(file, options) { |row| }
      true
    rescue FasterCSV::MalformedCSV
      false
    end
  end

end

Я использую этот метод следующим образом:

# /models/csv_importer.rb

class CsvImporter
  include ActiveRecord::Validations

  validates_presence_of :file
  validate check_file_format

...

  private

  def check_file_format
    errors.add :file, "Malformed CSV! Please check syntax" unless FasterCSV::is_valid? file
  end
end
0 голосов
/ 13 мая 2011

Вчера я провел несколько тестов, и оказалось, что мое решение не совсем сработало; Я продолжал получать пустые массивы на действительных CSV-файлах после реализации первого is_valid. Я не уверен, является ли это проблемой кэширования FasterCSV или чем-то в моем коде, и я не знаю, связано ли это с моей настройкой теста, но я решил вместо этого реализовать safe_parse:

#/lib/faster_csv_safe_parse.rb
class FasterCSV

  def self.safe_parse(file, options = {})
    begin
      FasterCSV.parse(file, options)
    rescue FasterCSV::MalformedCSVError
      nil
    end
  end

end

Это вернет проанализированный массив, если файл действителен, или nil в противном случае. Затем я мог бы реализовать свои проверки следующим образом:

# /models/csv_importer.rb

class CsvImporter
  include ActiveRecord::Validations

  validates_presence_of :file
  validate check_file_format
  attr_accessor csv_data

  def csv_data
    @csv_data ||= FasterCSV.safe_parse(file)
  end

...

  private

  def check_file_format
    errors.add :file, "Malformed CSV! Please check syntax" if csv_data.nil?
  end
end

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

0 голосов
/ 10 мая 2011

Я предполагаю, что вы хотите проанализировать CSV и сделать что-то с проанализированными результатами. В худшем случае ваш CSV-файл действителен и вы снова анализируете файл. Я написал бы что-то вроде этого, чтобы спрятать проанализированный результат, так что вам нужно только проанализировать CSV один раз:

module FasterCSV

  def self.parse_and_validate(file, options = {})

    begin
      @parsed_result = FasterCSV.parse(file, options) { |row| }
    rescue FasterCSV::MalformedCSV
      @invalid = true
    end
  end

  def self.is_valid?
    !@invalid
  end    

  def self.parsed_result
    @parsed_result if self.valid?
  end

end

А потом:

class CsvImporter
  include ActiveRecord::Validations

  validates_presence_of :file
  validate check_file_format

  # I assume you use the parsed result after the validations so in a before_save or something
  def do_your_parse_stuff
    here you would use FasterCSV::parsed_result
  end
...

  private

  def check_file_format
    FasterCSV::parse_and_validate(file)
    errors.add :file, "Malformed CSV! Please check syntax" unless FasterCSV::is_valid?
  end
end

В приведенном выше случае вы можете захотеть переместить материал в другой класс, который заботится о взаимодействии с FasterCSV и сохранении проанализированного результата, потому что я не думаю, что мой пример является поточно-ориентированным:)

...