2013-10-21 16 views
21

Attualmente sto usando scanner/lettore di file e utilizzo mentre hasnextline. Penso che questo metodo non sia molto efficiente. C'è qualche altro metodo per leggere il file con la funzionalità simile di questo?Java Il modo più veloce per leggere il file di testo con 2 milioni di righe

public void Read(String file) { 
     Scanner sc = null; 


     try { 
      sc = new Scanner(new FileReader(file)); 

      while (sc.hasNextLine()) { 
       String text = sc.nextLine(); 
       String[] file_Array = text.split(" ", 3); 

       if (file_Array[0].equalsIgnoreCase("case")) { 
        //do something 
       } else if (file_Array[0].equalsIgnoreCase("object")) { 
        //do something 
       } else if (file_Array[0].equalsIgnoreCase("classes")) { 
        //do something 
       } else if (file_Array[0].equalsIgnoreCase("function")) { 
        //do something 
       } 
       else if (file_Array[0].equalsIgnoreCase("ignore")) { 
        //do something 
       } 
       else if (file_Array[0].equalsIgnoreCase("display")) { 
        //do something 
       } 
      } 

     } catch (FileNotFoundException e) { 
      System.out.println("Input file " + file + " not found"); 
      System.exit(1); 
     } finally { 
      sc.close(); 
     } 
    } 
+0

questo [link] (http://www.geeksforgeeks.org/fast-io-in-java-in-competitive-programming/) ha alcune buone soluzioni – Joe

risposta

23

Troverete che BufferedReader.readLine() è veloce come è necessario: si può leggere milioni di righe al secondo con esso. È più probabile che la divisione e la gestione delle stringhe causino problemi di prestazioni che si verificano.

+0

ho fatto fare un controllo di tempo ma quando uso bufferedreader, penso che la parte di lettura sia circa il 20% più veloce rispetto allo scanner – BeyondProgrammer

+3

Nel mio caso, la divisione era il fattore più dominante nel file letto. L'uso semplice di indexOf/lastIndexOf e della sottostringa ha contribuito a ridurre tali costi al minimo. – lalitm

+0

Anche per me il costo è stato ridotto di circa il 50% una volta sostituito 'split()' con 'substring()' -'indexOf() 'pair. –

1

è possibile utilizzare FileChannel e ByteBuffer da JAVA NIO. La dimensione ByteBuffer è la parte più critica nella lettura dei dati più velocemente di quanto ho osservato. Il codice seguente leggerà il contenuto del file.

static public void main(String args[]) throws Exception 
    { 
     FileInputStream fileInputStream = new FileInputStream(
             new File("sample4.txt")); 
     FileChannel fileChannel = fileInputStream.getChannel(); 
     ByteBuffer byteBuffer = ByteBuffer.allocate(1024); 

     fileChannel.read(byteBuffer); 
     byteBuffer.flip(); 
     int limit = byteBuffer.limit(); 
     while(limit>0) 
     { 
      System.out.print((char)byteBuffer.get()); 
      limit--; 
     } 

     fileChannel.close(); 
    } 

È possibile controllare '\ n' per la nuova linea qui. Grazie.


Anche è possibile disperdere o modo getter per leggere i file più velocemente cioè

fileChannel.get(buffers); 

dove

 ByteBuffer b1 = ByteBuffer.allocate(B1); 
     ByteBuffer b2 = ByteBuffer.allocate(B2); 
     ByteBuffer b3 = ByteBuffer.allocate(B3); 

     ByteBuffer[] buffers = {b1, b2, b3}; 

Ciò consente di risparmiare il processo utente al di effettuare diverse chiamate di sistema (che può essere costoso) e consente al kernel di ottimizzare la gestione dei dati perché contiene informazioni sul trasferimento totale. Se sono disponibili più CPU, potrebbe essere possibile riempire e svuotare più buffer contemporaneamente sornione.

dal this libro.

+1

Un buffer di byte diretto non è di alcun beneficio se i dati vengono letti nel lato Java della JVM. Il suo vantaggio si ottiene se copi i dati tra due canali senza guardarli nel codice Java. – EJP

+0

@EJP lo so. Ho cancellato qui la linea e il tuo commento è arrivato. :-) – Trying

+0

@Prova, mi piacerebbe provare a utilizzare FileChannel potresti fornirmi un esempio dai miei codici sopra? – BeyondProgrammer

0

È necessario esaminare quale parte del programma richiede tempo.

Come per la risposta di EJP, è necessario utilizzare BufferedReader.

Se l'elaborazione delle stringhe richiede tempo, è consigliabile utilizzare i thread, un thread leggerà dalle righe di file e code. Altri thread del processore di stringa eliminano le righe e le elaborano. Dovrai indagare su quanti thread usare, il numero di thread che dovresti usare nell'applicazione deve essere correlato al numero di core nella CPU, in questo modo utilizzerai la CPU completa.

+0

In che modo l'aggiunta di thread corregge un problema di elaborazione delle stringhe? – EJP

+0

Se l'elaborazione delle stringhe richiede tempo, le pedate multiple che eseguono la stessa operazione diminuiranno il tempo, proprio come l'elaborazione parallela. – UDPLover

+0

Questo sarà utilizzabile solo quando l'elaborazione di una riga non dipende dall'elaborazione di un'altra linea. – UDPLover

-1

Se si desidera leggere tutte le righe insieme, è necessario dare un'occhiata all'API file di java 7. È davvero semplice da utilizzare.

Ma un approccio migliore sarebbe quello di elaborare questo file in un batch. Avere un lettore che legge pezzi di linee dal file e uno scrittore che esegue l'elaborazione richiesta o persiste i dati. Avere un controllo assicurerà che funzionerà anche se le linee aumenteranno a miliardi in futuro. Inoltre è possibile avere un batch che utilizza un multithreading per aumentare le prestazioni del batch. Ricordo che dai un'occhiata al lotto di primavera.

+0

In che modo esattamente un "batch" aiuta quando legge e processa una linea alla volta? – EJP

2

Lo scanner non può essere veloce poiché lo scanner utilizza espressioni regolari per la lettura di file di testo, il che lo rende più lento rispetto al lettore bufferizzato. Usando bufferedReader() puoi leggere un blocco dal file di testo.

BufferedReader bf = new BufferedReader(new FileReader("FileName")); 

è possibile utilizzare readLine() per leggere da bf.

auguro che serve il vostro scopo

+1

Penso che intendessi "Scanner non può essere veloce come BufferedReader" – anon58192932

0

Usa BufferedReader per l'accesso ai file ad alte prestazioni. Ma la dimensione del buffer di default di 8192 byte è spesso troppo piccola. Per i file di grandi dimensioni è possibile effettuare il increase the buffer size in base agli ordini di grandezza per migliorare le prestazioni di lettura dei file. Per esempio:

BufferedReader br = new BufferedReader("file.dat", 1000 * 8192); 
while ((thisLine = br.readLine()) != null) { 
    System.out.println(thisLine); 
} 
+0

Ma non avrà molto effetto. 8192 è sorprendentemente adeguato. – EJP

Problemi correlati