Ho un grosso file. Comprende circa 3.000-20.000 linee. Come posso ottenere il numero totale di righe nel file usando Java?Come posso ottenere il conteggio della linea in un file in modo efficiente?
risposta
BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
int lines = 0;
while (reader.readLine() != null) lines++;
reader.close();
Aggiornamento: Per rispondere alla performance questione sollevata qui, ho fatto una misura. Prima cosa: 20.000 linee sono troppo poche, per far funzionare il programma per un tempo notevole. Ho creato un file di testo con 5 milioni di righe. Questa soluzione (iniziata con java senza parametri come -server o -XX-options) aveva bisogno di circa 11 secondi sulla mia scatola. Lo stesso con wc -l
(UNIX command-line-tool per contare le linee), 11 secondi. La soluzione leggendo ogni singolo personaggio e cercando "\ n" aveva bisogno di 104 secondi, 9-10 volte tanto.
Che effetto intendi? Prestazione? In questo caso non avrai modo migliore, perché le linee possono avere lunghezze diverse dovrai leggere il file completo, per contare i numeri di riga (wc lo fa anche tu). Se parli di efficienza di programmazione, sono sicuro che puoi metterlo in un metodo di utilità (o qualche libreria comune lo ha già fatto). – Mnementh
@Firstthumb. Forse non efficiente, ma a chi importa. Sta contando solo 20k linee che sono piuttosto piccole. Questo codice ottiene il mio voto per essere il più semplice. –
come funziona l'efficienza di LineNumberReader dal momento che estende BufferedReader? – Narayan
Leggere il file e contare il numero di caratteri di nuova riga. Un modo semplice per leggere un file in Java, una riga alla volta, è la classe java.util.Scanner.
Leggere il file riga per riga e incrementare un contatore per ogni riga finché non si ha letto l'intero file.
uso LineNumberReader
qualcosa come
public static int countLines(File aFile) throws IOException {
LineNumberReader reader = null;
try {
reader = new LineNumberReader(new FileReader(aFile));
while ((reader.readLine()) != null);
return reader.getLineNumber();
} catch (Exception ex) {
return -1;
} finally {
if(reader != null)
reader.close();
}
}
Il lettore tamponata è eccessivo
Reader r = new FileReader("f.txt");
int count = 0;
int nextchar = 0;
while (nextchar != -1){
nextchar = r.read();
if (nextchar == Character.getNumericValue('\n')){
count++;
}
}
La mia ricerca di un semplice esempio è createde uno questo è in realtà piuttosto scarsa. chiamare read() ripetutamente per un singolo carattere non è ottimale. vedi here per esempi e misurazioni.
BufferedReader gestisce bene diverse terminazioni di linea. La tua soluzione ignora le terminazioni della linea Mac ('\ r'). Potrebbe essere OK. Ad ogni modo, la tua soluzione non viene effettivamente letta dal file al momento. Penso che tu abbia dimenticato una linea. – Mnementh
Che cosa cambierà nextchar qui? Se hai intenzione di chiamare read() ad ogni iterazione, sospetto fortemente che un approccio BufferedReader sarà * molto * più veloce ... –
è stata l'idea; -/Ho voluto scrivere l'esempio più semplice possibile. Mi chiedo quale sarebbe la differenza di velocità? – NSherwin
Tutte le risposte precedenti suggeriscono di leggere l'intero file e contare la quantità di nuove righe che si trovano durante l'operazione. Hai commentato alcuni come "non efficaci" ma questo è l'unico modo per farlo. Una "linea" non è nient'altro che un semplice carattere all'interno del file. E per contare quel personaggio devi dare un'occhiata a ogni singolo carattere all'interno del file.
Mi dispiace, ma non hai scelta. :-)
Se le risposte già pubblicate non sono abbastanza veloci, probabilmente dovrai cercare una soluzione specifica per il tuo particolare problema.
Ad esempio, se questi file di testo sono registri a cui si aggiungono solo i registri e regolarmente è necessario conoscere il numero di righe in essi contenute, è possibile creare un indice. Questo indice contiene il numero di righe nel file, quando il file è stato modificato l'ultima volta e quanto era grande il file. Questo ti permetterebbe di ricalcolare il numero di linee nel file saltando tutte le linee che avevi già visto e leggendo le nuove linee.
+1 questo potrebbe essere un algoritmo online adatto. – zeroin23
Probabilmente la soluzione più veloce in puro Java sarebbe quella di leggere il file come byte utilizzando un canale NIO in ByteBuffer di grandi dimensioni. Quindi, utilizzando le conoscenze dello schema di codifica dei file, si contano i byte codificati CR e/o NL, secondo la relativa convenzione del separatore di riga.
Le chiavi per il throughput massimizzare saranno:
- assicurarsi di leggere il file in grossi pezzi,
- evitare di copiare i byte da un buffer all'altro,
- evitare di copiare/byte conversione in caratteri e
- evitare di allocare oggetti per rappresentare le righe del file.
Il codice effettivo è troppo complicato per me da scrivere al volo. Inoltre, l'OP non sta chiedendo la soluzione più veloce.
Provare il comando "wc" di unix. Non intendo usarlo, voglio dire scaricare la fonte e vedere come lo fanno. Probabilmente è in c, ma puoi facilmente portare il comportamento a java. Il problema di crearne uno è quello di spiegare il problema finale di cr/lf.
Questo è quanto di efficiente quanto si può ottenere, tamponata lettura binaria, nessuna conversione di stringa,
FileInputStream stream = new FileInputStream("/tmp/test.txt");
byte[] buffer = new byte[8192];
int count = 0;
int n;
while ((n = stream.read(buffer)) > 0) {
for (int i = 0; i < n; i++) {
if (buffer[i] == '\n') count++;
}
}
stream.close();
System.out.println("Number of lines: " + count);
rapido e sporco, ma non il lavoro:
import java.io.*;
public class Counter {
public final static void main(String[] args) throws IOException {
if (args.length > 0) {
File file = new File(args[0]);
System.out.println(countLines(file));
}
}
public final static int countLines(File file) throws IOException {
ProcessBuilder builder = new ProcessBuilder("wc", "-l", file.getAbsolutePath());
Process process = builder.start();
InputStream in = process.getInputStream();
LineNumberReader reader = new LineNumberReader(new InputStreamReader(in));
String line = reader.readLine();
if (line != null) {
return Integer.parseInt(line.trim().split(" ")[0]);
} else {
return -1;
}
}
}
Un effetto collaterale, questa soluzione non è multipiattaforma. – Stephan
ho trovato qualche soluzione per questo, potrebbe essere utile per voi
Di seguito è riportato il frammento di codice per, conteggiare il numero di righe dal file.
File file = new File("/mnt/sdcard/abc.txt");
LineNumberReader lineNumberReader = new LineNumberReader(new FileReader(file));
lineNumberReader.skip(Long.MAX_VALUE);
int lines = lineNumberReader.getLineNumber();
lineNumberReader.close();
il risultato è line' count - 1' – MariuszS
il risultato è 'lines + 1' –
il risultato è getLineNumber() più 1 perché l'indice di riga inizia da 0 –
Hai bisogno del numero esatto di linee o solo la sua approssimazione? Mi capita di elaborare file di grandi dimensioni in parallelo e spesso non ho bisogno di sapere il conteggio esatto delle linee - poi tornerò al campionamento. Dividi il file in dieci blocchi da 1MB e conta le linee in ogni blocco, quindi moltiplicalo per 10 e otterrai un'approssimazione abbastanza buona del conteggio delle righe.
Questa soluzione è circa 3,6 × più veloce della risposta più votata quando viene testata su un file con 13,8 milioni di righe. Legge semplicemente i byte in un buffer e conta i caratteri \n
. Si potrebbe giocare con la dimensione del buffer, ma sulla mia macchina, qualsiasi valore superiore a 8 KB non ha reso il codice più veloce.
private int countLines(File file) throws IOException {
int lines = 0;
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[BUFFER_SIZE]; // BUFFER_SIZE = 8 * 1024
int read;
while ((read = fis.read(buffer)) != -1) {
for (int i = 0; i < read; i++) {
if (buffer[i] == '\n') lines++;
}
}
fis.close();
return lines;
}
Mi chiedo se l'utilizzo di un modello RegEx precompilato lo renderebbe più veloce o più lento.Quello che farebbe funzionare con tutte le terminazioni di linea, credo. E penso che potrebbe renderlo anche più veloce. – ingyhere
Alcune delle soluzioni di cui sopra possono trarre vantaggio dal buffering, inoltre, se i vantaggi sarebbero di aiuto. Ad esempio, "new LineNumberReader (new FileReader (theFilePathStr), 8096)" o qualcosa del genere. – ingyhere
Prestare attenzione alle codifiche dei caratteri ... Soluzione letto –
Vecchio post, ma ho una soluzione che potrebbe essere utile per la prossima gente. Perché non usare solo la lunghezza del file per sapere qual è la progressione? Naturalmente, le linee deve essere quasi la stessa dimensione, ma funziona molto bene per file di grandi dimensioni:
public static void main(String[] args) throws IOException {
File file = new File("yourfilehere");
double fileSize = file.length();
System.out.println("=======> File size = " + fileSize);
InputStream inputStream = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "iso-8859-1");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
int totalRead = 0;
try {
while (bufferedReader.ready()) {
String line = bufferedReader.readLine();
// LINE PROCESSING HERE
totalRead += line.length() + 1; // we add +1 byte for the newline char.
System.out.println("Progress ===> " + ((totalRead/fileSize) * 100) + " %");
}
} finally {
bufferedReader.close();
}
}
Permette di vedere la progressione senza fare alcun Leggi l'articolo completo sul file. So che dipende da molti elementi, ma spero che sarà utile :).
[Edizione] Ecco una versione con tempo stimato. Ho messo un po 'di SYSO per mostrare i progressi e la stima. Vedo che hai errori di stima del buon tempo dopo aver trattato una riga sufficiente (provo con le linee 10M e dopo l'1% del trattamento, la stima del tempo era esatta al 95%). Lo so, alcuni valori devono essere impostati in variabile. Questo codice è scritto rapidamente ma è utile per me. Spero che lo sarà anche per te :).
long startProcessLine = System.currentTimeMillis();
int totalRead = 0;
long progressTime = 0;
double percent = 0;
int i = 0;
int j = 0;
int fullEstimation = 0;
try {
while (bufferedReader.ready()) {
String line = bufferedReader.readLine();
totalRead += line.length() + 1;
progressTime = System.currentTimeMillis() - startProcessLine;
percent = (double) totalRead/fileSize * 100;
if ((percent > 1) && i % 10000 == 0) {
int estimation = (int) ((progressTime/percent) * (100 - percent));
fullEstimation += progressTime + estimation;
j++;
System.out.print("Progress ===> " + percent + " %");
System.out.print(" - current progress : " + (progressTime) + " milliseconds");
System.out.print(" - Will be finished in ===> " + estimation + " milliseconds");
System.out.println(" - estimated full time => " + (progressTime + estimation));
}
i++;
}
} finally {
bufferedReader.close();
}
System.out.println("Ended in " + (progressTime) + " seconds");
System.out.println("Estimative average ===> " + (fullEstimation/j));
System.out.println("Difference: " + ((((double) 100/(double) progressTime)) * (progressTime - (fullEstimation/j))) + "%");
Sentiti libero di migliorare questo codice se pensi che sia una buona soluzione.
Nei miei test, le altre risposte richiedono ~ 150-300 ms su un file di linea 118.5k. Quanto segue richiede 1 ms ma è solo approssimativo (riporta linee 117k) e dipende dal fatto che ogni linea abbia una dimensione simile.
private static void countSize(File file) {
long fileLength = file.length();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
//Skip header as it is of different size
reader.readLine();
String text = reader.readLine();
int lineLength = text.length();
long lines = fileLength/lineLength;
System.out.println(lines);
} catch(IOException e) {
e.printStackTrace();
} finally {
if(reader != null) {
try {
reader.close();
} catch(IOException e) {
//no-op
}
}
}
}
Java 8+ ha un modo molto bello e breve con NIO:
Path path = Paths.get("./big_file.txt");
long lineCount = Files.lines(path).count();
. possiamo avere un problema con il set di caratteri – Mikhail
il set di caratteri è UTF-8 per impostazione predefinita –
- 1. Come posso indicizzare in modo efficiente un file?
- 2. Come precaricare in modo efficiente una linea in un file di grandi dimensioni in PowerShell
- 3. Ottenere linea conteggio di tutti i file in progetti in modo ordinato. (Terminale Bash)
- 4. Come posso implementare java.awt.Composite in modo efficiente?
- 5. trovare sottoinsieme di record in modo efficiente e conteggio totale
- 6. Come posso modificare il testo in un flusso in modo efficiente, in un componente della pipeline BizTalk?
- 7. Come ottenere il conteggio totale delle partite in Solr/lucene
- 8. Come ottenere il conteggio NSMutableDictionary in iphone?
- 9. Ottenere il conteggio dei file in una directory
- 10. In che modo Objective-C fa riferimento al conteggio in modo efficiente?
- 11. Come posso ottenere il nome di un file in Dart?
- 12. Come includere in modo efficiente config.php?
- 13. Il modo più efficiente per ottenere diversi hash in Redis?
- 14. Come posso convertire un InputStream non compresso in un InputStream gzip in modo efficiente?
- 15. Come dividere in modo efficiente file di grandi dimensioni
- 16. Come posso spostare in modo efficiente molti file su un nuovo server?
- 17. Come posso ottenere in modo efficiente un sottoinsieme di un array di byte (primi N elementi) in C#?
- 18. ottenere conteggio query in SQL
- 19. Come dividere un file in righe in cammello ma il processo della prima linea in modo diverso
- 20. Come posso individuare un tipo specifico in un assieme * in modo efficiente *?
- 21. Come posso trasformare in modo efficiente un array numpy.int8 in un array numpy.uint8 con valori spostati?
- 22. Come ottenere il numero di linea della funzione (con/senza un decoratore) in un modulo python?
- 23. Come posso implementare questa in modo più efficiente
- 24. Come posso riutilizzare una connessione HttpClient in modo efficiente?
- 25. Come annullare in modo efficiente un completamento automatico in vim
- 26. Il modo più efficiente per creare un indice in Postgres
- 27. Leggere in modo efficiente file di testo di grandi dimensioni
- 28. Come utilizzare in modo efficiente MySQLDB SScursor?
- 29. Il modo più efficiente per ottenere tutto il valore per un campo in MongoDB e Node.js
- 30. Ottieni il conteggio dei file selezionati in dropzone
A giudicare dai vostri commenti alle risposte, la parola che stai cercando è 'efficiente', non e 'efficace' . – AakashM
Sì, hai ragione. – firstthumb
@Firstthumb: per favore non eliminare i commenti * dopo * le persone hanno risposto a loro. Rende il thread confuso per le persone che arrivano in ritardo allo show. – Telemachus