2009-07-07 11 views
6

Soy bastante nuevo en programación, así que sea amable. Estoy tratando de extraer los números IBSN de un archivo .dat de la base de datos de la biblioteca. He escrito un código que funciona, pero solo está buscando aproximadamente la mitad del archivo de 180 MB. ¿Cómo puedo ajustarlo para buscar todo el archivo? ¿O cómo puedo escribir un programa que dividirá el archivo dat en fragmentos manejables?¿Cómo puedo manejar archivos grandes en Ruby?

edición: Aquí está mi código:

export = File.new("resultsfinal.txt","w+") 

File.open("bibrec2.dat").each do |line| 
    line.scan(/[a]{1}[1234567890xX]{10}\W/) do |x| 
    export.puts x 
    end 
    line.scan(/[a]{1}[1234567890xX]{13}/) do |x| 
    export.puts x 
    end 
end 
+0

@ zed_0xff: El enfoque de Yoann Le Touche no leyó un archivo completo en la memoria. –

Respuesta

-2

Si está programando en un sistema operativo moderno y el equipo tiene suficiente memoria (digamos 512megs), Ruby no debe tener ningún problema al leer el archivo en la memoria .

Las cosas suelen ser dudosas cuando se llega a un conjunto de trabajo de 2 gigabytes en un sistema operativo de 32 bits típico.

+0

Bueno, el mío se está poniendo dudoso con 4GB en Vista, si eso ayuda. Además, no genera un error, solo un conjunto incompleto de resultados. –

+0

Creo que quiere decir que los datos son de 4GB, no del tamaño de tu memoria. Los sistemas operativos de 32 bits no pueden manejar más de aproximadamente ~ 3.5 GB de RAM, por lo que no tienes 4 GB de RAM de trabajo a tu disposición, independientemente (a menos que estés ejecutando Vista de 64 bits). Si su conjunto de datos es solo de 180 MB, el problema debe estar en su código. ¿Publicaras el guion? – jkeys

+0

No hay problema, lo publicaré mañana. Muchas gracias. –

1

En cuanto al problema de rendimiento, no veo nada particularmente preocupante sobre el tamaño del archivo: 180 MB no debería plantear ningún problema. ¿Qué sucede con el uso de la memoria cuando estás ejecutando tu script?

No estoy seguro, sin embargo, de que sus expresiones regulares hagan lo que usted desea. Esto, por ejemplo:

/[a]{1}[1234567890xX]{10}\W/ 

va (creo) esto:

  • una "a". ¿De verdad quieres unir para una "a"? "a" sería suficiente, en lugar de "[a] {1}", en ese caso.
  • exactamente 10 (dígito o "x" o "X")
  • un solo "no-palabra" carácter es decir, no az, AZ, 0-9 o guión

Hay un par de ejemplos de equivalentes ISBN here y here, aunque parecen coincidir con algo más parecido al formato que vemos en la contraportada de un libro y supongo que su archivo de entrada ha eliminado algo de ese formato.

+0

Sí, el archivo de datos original ha reformateado los ISBN para que estén en ese formato. ¡No tengo idea de por qué se hace eso! Una buena llamada al escribir 'a', parece mucho más simple. –

4

Debe intentar detectar excepciones para comprobar si el problema está realmente en el bloque de lectura o no.

Solo para que sepa que ya hice un script con la misma sintaxis para buscar archivos grandes de ~ 8GB sin problema.

export = File.new("resultsfinal.txt","w+") 

File.open("bibrec2.dat").each do |line| 
    begin 
    line.scan(/[a]{1}[1234567890xX]{10}\W/) do |x| 
     export.puts x 
    end 
    line.scan(/[a]{1}[1234567890xX]{13}/) do |x| 
     export.puts x 
    end 
    rescue 
    puts "Problem while adding the result" 
    end 
end 
2
file = File.new("bibrec2.dat", "r") 
while (line = file.gets) 
    line.scan(/[a]{1}[1234567890xX]{10}\W/) do |x| 
    export.puts x 
    end 
    line.scan(/[a]{1}[1234567890xX]{13}/) do |x| 
    export.puts x 
    end 
end 
file.close 
3

Lo principal es limpiar y combinar la expresión regular para los beneficios de rendimiento. Además, siempre debe usar la sintaxis de bloque con los archivos para asegurarse de que los fd se cierren correctamente. File # cada uno no se carga todo el archivo en la memoria, se hace una línea a la vez:

File.open("resultsfinal.txt","w+") do |output| 
    File.open("bibrec2.dat").each do |line| 
     output.puts line.scan(/a[\dxX]{10}(?:[\dxX]{3}|\W)/) 
    end 
end 
1

Puede ver en el uso File#truncate y IO#seek y emplear el algoritmo de búsqueda de tipo binario. #truncate puede ser destructivo por lo que debe duplicar el archivo (sé que esto es una molestia).

middle = File.new("my_huge_file.dat").size/2 
tmpfile = File.new("my_huge_file.dat", "r+").truncate(middle) 
# run search algoritm on 'tmpfile' 
File.open("my_huge_file.dat") do |huge_file| 
    huge_file.seek(middle + 1) 
    # run search algorithm from here 
end 

El código es muy no probado, frágil e incompleto. Pero espero que te brinde una plataforma para construir.

+0

¿Qué sucede si divide su archivo en el medio de una línea? ;) – fenec

Cuestiones relacionadas