Вопрос

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

# write
io.print "%i %s %s\n" % [File.mtime(fname), fname, Digest::SHA1.file(fname).hexdigest]
# read
io.each do |line|
  mtime, name, hash = line.scanf "%i %s %s"
end

Конечно, это не работает, потому что имя файла может содержать пробелы (разрывное Scanf) и разрывы линии (ломающиеся IO # каждый).

Проблема разбития линии можно избежать, отбросив использование каждого и собираясь с кучей Get ('')

while not io.eof?
  mtime = Time.at(io.gets(" ").to_i)
  name = io.gets " "
  hash = io.gets "\n"
end

Работа с пробелами в именах - это другое дело. Теперь нам нужно сделать некоторые выбеги.
ПРИМЕЧАНИЕ. Мне нравится пространство в качестве разделителя записи, но у меня не было никакой проблемы, изменив ее, чтобы кто-то легче использовать. Однако в случае имена файлов единственная, что может помочь, это ASCII NUL « 0», но файл для разграничения Nul больше не является текстовым файлом ...

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

def write_name(io, val)
  io << val.gsub(/([\\ ])/, "\\\\\\1") # yes that' 6 backslashes !
end

def read_name(io)
  name, continued = "", true
  while continued
    continued = false
    name += io.gets(' ').gsub(/\\(.)/) do |c|
      if c=="\\\\"
        "\\"
      elsif c=="\\ "
        continued=true
        " "
      else
        raise "unexpected backslash escape  : %p (%s %i)" % [c, io.path, io.pos]
      end
    end
  end
  return name.chomp(' ')
end

Я совсем не счастлив с read_name. Слишком долго и Akward, я чувствую, что не должен быть так сложно.

При попытке сделать эту работу, я пытался придумать другие способы:

  • BitTorrent Conded / PHP Serialize Way: префикс имени файла с длиной имени, а затем только io.read (name_len.to_i). Это работает, но это настоящая пита для редактирования файла вручную. На данный момент мы на полпути к двоичному формату.

  • String # Осмотрите: этот выглядит прямо для этой цели! За исключением того, что это похоже на единственный способ получить значение обратно через Eval. Я ненавижу идею Eval-ing a String, которую я не генерировал от доверенных данных.

Так. Мнения? Разве есть ли некоторые lib, которые могут сделать все это? Я упускаю что-то очевидное? Как бы Вы это сделали ?

Это было полезно?

Решение

Когда вы говорите «Сохранить», вы имеете в виду магазин информации в файле?

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

  • Если значение содержит пробелы, что значение прилагается в "quotes"

  • Если значение содержит цитаты, то символ цитаты сбежен как 2 символа цитата, например, "hello" станет """hello"""

Чтобы написать детали в файл:

require 'csv'

outfile = File.open('csvout', 'wb')
CSV::Writer.generate(outfile) do |csv|
  csv << [File.mtime(fname), fname, Digest::SHA1.file(fname).hexdigest]
end
outfile.close

Прочитать их обратно:

CSV::Reader.parse(File.open('csvout', 'rb')) do |row|
  p row
end

Другие советы

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

require 'pp'
require 'yaml'

h = {
  :first_name => 'Fred',
  :last_name => 'Flinstone',
  :children => ['Bam Bam', 'Pebbles'],
  :exclamation => 'Yabba Dabba Doo',
}

Давайте напишем данные в файл в формате YAML:

File.open('/tmp/foo.yaml', 'w') do |file|
  file.write h.to_yaml
end

Теперь давайте посмотрим, как выглядит YAML:

$ cat /tmp/foo.yaml
---
:exclamation: Yabba Dabba Doo
:first_name: Fred
:last_name: Flinstone
:children:
- Bam Bam
- Pebbles

И, наконец, давайте восстановим данные из файла yaml:

pp YAML.load_file('/tmp/foo.yaml')
# => {:exclamation=>"Yabba Dabba Doo",
# =>  :first_name=>"Fred",
# =>  :last_name=>"Flinstone",
# =>  :children=>["Bam Bam", "Pebbles"]}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top