Esta es la versión más rápida que he encontrado hasta ahora, aproximadamente 6 veces más rápido que readLines. En un archivo de registro de 150 MB, esto lleva 0,35 segundos, frente a 2,40 segundos cuando se usa readLines (). Solo por diversión, el comando wc -l de linux tarda 0,15 segundos.
public static int countLinesOld(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int count = 0;
int readChars = 0;
boolean empty = true;
while ((readChars = is.read(c)) != -1) {
empty = false;
for (int i = 0; i < readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
}
return (count == 0 && !empty) ? 1 : count;
} finally {
is.close();
}
}
EDITAR, 9 años y medio después: prácticamente no tengo experiencia en Java, pero de todos modos he tratado de comparar este código con la LineNumberReader
solución a continuación, ya que me molestó que nadie lo hiciera. Parece que, especialmente para archivos grandes, mi solución es más rápida. Aunque parece tomar algunas carreras hasta que el optimizador hace un trabajo decente. He jugado un poco con el código y he producido una nueva versión que es consistentemente más rápida:
public static int countLinesNew(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int readChars = is.read(c);
if (readChars == -1) {
// bail out if nothing to read
return 0;
}
// make it easy for the optimizer to tune this loop
int count = 0;
while (readChars == 1024) {
for (int i=0; i<1024;) {
if (c[i++] == '\n') {
++count;
}
}
readChars = is.read(c);
}
// count remaining characters
while (readChars != -1) {
System.out.println(readChars);
for (int i=0; i<readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
readChars = is.read(c);
}
return count == 0 ? 1 : count;
} finally {
is.close();
}
}
Resultados de referencia para un archivo de texto de 1.3GB, eje y en segundos. He realizado 100 ejecuciones con el mismo archivo, y he medido cada ejecución con System.nanoTime()
. Puede ver que countLinesOld
tiene algunos valores atípicos y countLinesNew
ninguno, y aunque es solo un poco más rápido, la diferencia es estadísticamente significativa. LineNumberReader
Es claramente más lento.
He implementado otra solución al problema, lo encontré más eficiente al contar filas:
fuente
LineNumberReader
EllineNumber
campo de 'es un número entero ... ¿No se ajustará solo a los archivos más largos que Integer.MAX_VALUE? ¿Por qué molestarse en pasar tanto tiempo aquí?wc -l
cuenta el número de caracteres de nueva línea en el archivo. Esto funciona ya que cada línea se termina con una nueva línea, incluida la línea final en un archivo. Cada línea tiene un carácter de nueva línea, incluidas las líneas vacías, de ahí que el número de caracteres de nueva línea == número de líneas en un archivo. Ahora, lalineNumber
variable enFileNumberReader
también representa el número de caracteres de nueva línea vistos. Comienza en cero, antes de que se encuentre una nueva línea, y aumenta con cada carácter de nueva línea visto. Así que no agregue uno al número de línea por favor.wc -l
también se informa este tipo de archivo. Ver también stackoverflow.com/questions/729692/…wc -l
devolvería 1. Llegué a la conclusión de que todos los métodos tienen fallas, e implementé uno basado en cómo me gustaría que se comportara, vea mi otra respuesta aquí.La respuesta aceptada tiene un error de uno por uno para los archivos de varias líneas que no terminan en nueva línea. Un archivo de una línea que termina sin una nueva línea devolvería 1, pero un archivo de dos líneas que termina sin una nueva línea también devolvería 1. Aquí hay una implementación de la solución aceptada que soluciona esto. Las comprobaciones finalesWithoutNewLine son un desperdicio para todo menos la lectura final, pero deben ser triviales en cuanto al tiempo en comparación con la función general.
fuente
Con java-8, puedes usar transmisiones:
fuente
La respuesta con el método count () anterior me dio un recuento incorrecto de líneas si un archivo no tenía una nueva línea al final del archivo; no se pudo contar la última línea del archivo.
Este método funciona mejor para mí:
fuente
cnt
.Sé que esta es una vieja pregunta, pero la solución aceptada no coincidía con lo que necesitaba hacer. Entonces, lo refiné para aceptar varios terminadores de línea (en lugar de solo un avance de línea) y para usar una codificación de caracteres específica (en lugar de ISO-8859- n ). Método todo en uno (refactorizar según corresponda):
Esta solución es comparable en velocidad a la solución aceptada, aproximadamente un 4% más lenta en mis pruebas (aunque las pruebas de temporización en Java son notoriamente poco confiables).
fuente
Probé los métodos anteriores para contar líneas y aquí están mis observaciones para diferentes métodos según lo probado en mi sistema
Tamaño de archivo: 1.6 Gb Métodos:
Además, el enfoque Java8 parece bastante útil:
fuente
Probado en JDK8_u31. Pero, de hecho, el rendimiento es lento en comparación con este método:
Probado y muy rápido.
fuente
Stream<String> - Time consumed: 122796351 Stream<String> - Num lines: 109808 Method - Time consumed: 12838000 Method - Num lines: 1
Y el número de líneas es aún demasiado malBufferedInputStream
todos modos no debe usar a cuando vaya a leer en su propio búfer. Además, incluso si su método puede tener una ligera ventaja de rendimiento, pierde flexibilidad, ya que ya no admite\r
terminadores de línea única (MacOS antiguo) y no admite todas las codificaciones.Una forma sencilla de usar el escáner
fuente
Llegué a la conclusión de que
wc -l
: el método de contar nuevas líneas está bien, pero devuelve resultados no intuitivos en archivos donde la última línea no termina con una nueva línea.Y la solución @ er.vikas basada en LineNumberReader pero agregando uno al recuento de líneas devolvió resultados no intuitivos en archivos donde la última línea termina con nueva línea.
Por lo tanto, hice un algo que se maneja de la siguiente manera:
Y se ve así:
Si desea resultados intuitivos, puede usar esto. Si solo desea
wc -l
compatibilidad, simplemente use la solución @ er.vikas, pero no agregue una al resultado y vuelva a intentar omitirla:fuente
¿Qué tal usar la clase Process desde el código Java? Y luego leyendo la salida del comando.
Aunque necesito probarlo. Publicará los resultados.
fuente
Si no tiene ninguna estructura de índice, no obtendrá la lectura del archivo completo. Pero puede optimizarlo evitando leerlo línea por línea y usar una expresión regular para que coincida con todos los terminadores de línea.
fuente
¡Esta divertida solución funciona realmente bien!
fuente
En sistemas basados en Unix, use el
wc
comando en la línea de comandos.fuente
La única forma de saber cuántas líneas hay en el archivo es contarlas. Por supuesto, puede crear una métrica a partir de sus datos para obtener una longitud promedio de una línea y luego obtener el tamaño del archivo y dividirlo con prom. longitud pero eso no será exacto.
fuente
Mejor código optimizado para archivos de varias líneas que no tienen carácter de nueva línea ('\ n') en EOF.
fuente
Escáner con expresiones regulares:
No lo he marcado.
fuente
si usas esto
no puede correr a grandes filas numéricas, le gustan las filas de 100K, porque el retorno de reader.getLineNumber es int. necesita un tipo de datos largo para procesar filas máximas.
fuente
int
puede contener valores de hasta, aproximadamente, 2 mil millones. Si está cargando un archivo con más de 2 mil millones de líneas, tiene un problema de desbordamiento. Dicho esto, si está cargando un archivo de texto no indexado con más de dos mil millones de líneas, probablemente tenga otros problemas.