2012-01-12 17 views
7

Estoy trabajando con un archivo de texto muy grande (755Mb). Necesito ordenar las líneas (alrededor de 1890000) y luego escribirlas en otro archivo.ordenando líneas de un enorme archivo.txt en java

ya me di cuenta de que la discusión que tiene un archivo de partida muy similar a la mía: Sorting Lines Based on words in them as keys

El problema es que no puedo almacenar las líneas en una colección en la memoria porque me sale una excepción montón de Java Espacio (incluso si he ampliado al máximo) .. (bastante bueno en!)

que o bien no se puede abrir con Excel y usar la característica de ordenación debido a que el archivo es demasiado grande y no puede ser completamente cargada ..

I pensado en usar un DB ... pero creo que escribir todas las líneas, entonces la consulta SELECT es demasiado larga en términos de tiempo de ejecución ... ¿estoy equivocado?

Alguna pista apreciados Gracias de antemano

+0

Bueno, "demasiado tiempo" depende de sus expectativas. Si esperas hacerlo en medio segundo, de hecho será demasiado largo. Si no te importa esperar unos segundos o minutos, no debería ser un problema. Pruébalo y mira si el tiempo es razonable. –

+0

Debería poder almacenar el archivo en la memoria con aproximadamente 1 GB de heap usando las últimas versiones de Java. es decir con '-XX: + UseCompressedStrings' –

Respuesta

15

creo que la solución a este problema es hacer una combinación de clase usando los archivos temporales:

  1. Lea las primeras n líneas del primer archivo, (n siendo el número de líneas que puede almacenar y clasificar en la memoria), ordénelas y escríbalas en el archivo 1.tmp (o como lo llame). Haga lo mismo con las siguientes líneas n y guárdelo en 2.tmp. Repita hasta que todas las líneas del archivo original hayan sido procesadas.

  2. Lea la primera línea de cada archivo temporal. Determine el más pequeño (según su orden de clasificación), escríbalo en el archivo de destino y lea la siguiente línea del archivo temporal correspondiente. Repita hasta que todas las líneas hayan sido procesadas.

  3. Borrar todos los archivos temporales.

Esto funciona con archivos grandes arbitrarios, siempre que tenga suficiente espacio en disco.

+0

Estoy totalmente de acuerdo. Se puede hacer utilizando el algoritmo 'mergesort' –

+4

+1 Esto se llama "mergesort multidireccional". – Tudor

0

¿Por qué no pruebas multihilo y el aumento de tamaño de la pila del programa que se está ejecutando? (Esto también requiere el uso de ordenamiento por mezcla tipo de cosas siempre que disponga de más memoria de 755mb en su sistema.)

+0

Vea el comentario dejado para Eric.Sun arriba. –

+0

Sí, su razón es obviamente útil en tamaño de archivo muy grande. Pero el tamaño de archivo especificado OP es 755mb y la mayoría de las computadoras hoy en día tienen más de 755mb. ¿Por qué usar un algoritmo complejo si podemos resolver su problema con solo -Xmx1024m? – javaCity

+1

Merge sort no es un algoritmo demasiado complejo. No quería hacer suposiciones sobre el hardware utilizado por el algoritmo. Además, el proceso puede no ser el único software que se ejecuta en el dispositivo. En mi humilde opinión, escribir 50 líneas de código para ahorrar más de un GB de memoria (cada línea puede ocupar varios bytes, si es una cadena) bien vale la pena el esfuerzo. (Sin intención de ofender.) –

1

algoritmo:

¿Cuánta memoria tenemos disponibles? Supongamos que tenemos X MB de memoria disponible.

  1. Dividir el archivo en trozos K, donde X * K = 2 GB. Traiga cada fragmento a la memoria y ordene las líneas de la forma habitual utilizando cualquier algoritmo O(n log n). Guarde las líneas nuevamente en el archivo.

  2. Ahora traiga el siguiente fragmento en la memoria y ordene.

  3. Una vez que hayamos terminado, combínalos uno por uno.

El algoritmo anterior también se conoce como clasificación externa. El paso 3 se conoce como N-way merge

-2

Quizás pueda usar perl para formatear el archivo .y cargarlo en la base de datos como mysql. es tan rápido y usa el índice para consultar los datos. y escribe en otro archivo.

u puede establecer el tamaño de pila de JVM como .i '-Xms256m -Xmx1024M' esperanza de ayudar u .thanks

+0

Usar una clasificación por fusión basada en archivos es mucho mejor que simplemente asignar más memoria. ¿Qué sucede si el archivo es aún más grande, es decir, 10gigs? –

1

puede ejecutar el siguiente con

-mx1g -XX:+UseCompressedStrings # on Java 6 update 29 
-mx1800m -XX:-UseCompressedStrings # on Java 6 update 29 
-mx2g # on Java 7 update 2. 

import java.io.*; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 

public class Main { 
    public static void main(String... args) throws IOException { 
     long start = System.nanoTime(); 
     generateFile("lines.txt", 755 * 1024 * 1024, 189000); 

     List<String> lines = loadLines("lines.txt"); 

     System.out.println("Sorting file"); 
     Collections.sort(lines); 
     System.out.println("... Sorted file"); 
     // save lines. 
     long time = System.nanoTime() - start; 
     System.out.printf("Took %.3f second to read, sort and write to a file%n", time/1e9); 
    } 

    private static void generateFile(String fileName, int size, int lines) throws FileNotFoundException { 
     System.out.println("Creating file to load"); 
     int lineSize = size/lines; 
     StringBuilder sb = new StringBuilder(); 
     while (sb.length() < lineSize) sb.append('-'); 
     String padding = sb.toString(); 

     PrintWriter pw = new PrintWriter(fileName); 
     for (int i = 0; i < lines; i++) { 
      String text = (i + padding).substring(0, lineSize); 
      pw.println(text); 
     } 
     pw.close(); 
     System.out.println("... Created file to load"); 
    } 

    private static List<String> loadLines(String fileName) throws IOException { 
     System.out.println("Reading file"); 
     BufferedReader br = new BufferedReader(new FileReader(fileName)); 
     List<String> ret = new ArrayList<String>(); 
     String line; 
     while ((line = br.readLine()) != null) 
      ret.add(line); 
     System.out.println("... Read file."); 
     return ret; 
    } 
} 

impresiones

Creating file to load 
... Created file to load 
Reading file 
... Read file. 
Sorting file 
... Sorted file 
Took 4.886 second to read, sort and write to a file 
+0

¿Puedes repetir la prueba usando jdk7u2 para ver cuánta memoria y tiempo lleva? – dogbane

+0

Desafortunadamente Java 7 no es compatible con esta opción http://stackoverflow.com/questions/8833385/is-support-for-compressed-strings-being-dropped –

+0

Sí, pero aún me gustaría ver cuánta memoria usa sin la opción. Tal vez hayan realizado mejoras tales que esta opción ya no es necesaria. – dogbane