Pregunta

necesito para ahorrar unos cuantos informaciones sobre algunos archivos. Nada lujoso, así que pensé que iría con un simple una línea por cada archivo de texto del elemento. Algo como esto:

# 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

Por supuesto, esto no funciona debido a un nombre de archivo puede contener espacios (scanf romper) y saltos de línea (IO # rompiendo cada uno).

El problema salto de línea se puede evitar dejar caer el uso de cada uno y va con un manojo de gets (' ')

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

Tratamiento de espacios en los nombres es otra cosa. Ahora tenemos que hacer un poco de escape.
nota: me gusta el espacio como un delimitador de registro, pero no tendría ningún problema cambiándolo por uno más fácil de usar. En el caso de los nombres de archivo, sin embargo, el único que podría ayudar es nulo ASCII "\ 0", sino un fichero nulo delimitado no es realmente un archivo de texto ya ...

Yo inicialmente tenía un muro de texto que detalla las iteraciones de mi lucha para hacer una función de escape correcta y su recíproco pero fue simplemente aburrido y no es realmente útil. Sólo te voy a dar el resultado final:

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

No estoy contento en absoluto con read_name. Demasiado tiempo y sus inconveniencias, siento que no debería ser tan difícil.

Al tratar de hacer este trabajo he tratado de llegar a otras formas:

  • el bittorrent codificada / php serialize manera: prefijo del nombre de archivo con la longitud del nombre de a continuación, sólo io.read (name_len.to_i). Funciona pero es un verdadero pita para editar el archivo manualmente. En este momento estamos a mitad de camino a un formato binario.

  • Cadena # inspeccionar: Éste parece hecha expresamente para este fin! Salvo que parece que la única manera de conseguir la espalda valor es a través de eval. No me gusta la idea de eval-ción de una cadena que no generaron a partir de datos de confianza.

Así. Opiniones? ¿No hay alguna lib que puede hacer todo esto? Me estoy perdiendo algo obvio? ¿Cómo hacer eso?

¿Fue útil?

Solución

Cuando se dice "Guardar" S guarda media la información en un archivo?

Se podría utilizar el CSV módulo del Rubí Biblioteca estándar. Esto significaría que el delimitador es una coma en lugar de espacio, sino que se ocuparía de todo el escape y la representación no literal para usted.

  • Si un valor contiene espacios que el valor está encerrado en "quotes"

  • Si un valor contiene comillas a continuación, un carácter de comillas se escapó como 2 caracteres de comillas, por ejemplo, "hello" se convertiría en """hello"""

Para escribir los datos en un archivo:

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

Para leer de nuevo:

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

Otros consejos

CSV, como se ha mencionado, es una opción buena. Otra es YAML ( "Yaml no es un lenguaje de marcado"), que puede manejar datos más arbitraria que CSV lata. He aquí algunos datos:

require 'pp'
require 'yaml'

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

Vamos a escribir los datos en un archivo en formato YAML:

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

Ahora vamos a ver lo que ve el YAML como:

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

Y finalmente vamos a reconstituir los datos del archivo YAML:

pp YAML.load_file('/tmp/foo.yaml')
# => {:exclamation=>"Yabba Dabba Doo",
# =>  :first_name=>"Fred",
# =>  :last_name=>"Flinstone",
# =>  :children=>["Bam Bam", "Pebbles"]}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top