una txt texto sobreescribir por lineas linea leer fin especifica ejemplos contar como archivos archivo java large-files line-numbers

txt - leer una linea especifica de un archivo en java



Número de líneas en un archivo en Java (17)

¡Esta solución divertida funciona realmente bien en realidad!

public static int countLines(File input) throws IOException { try (InputStream is = new FileInputStream(input)) { int count = 1; for (int aChar = 0; aChar != -1;aChar = is.read()) count += aChar == ''/n'' ? 1 : 0; return count; } }

Utilizo archivos de datos enormes, a veces solo necesito saber la cantidad de líneas en estos archivos, generalmente los abro y los leo línea por línea hasta que llego al final del archivo.

Me preguntaba si hay una forma más inteligente de hacerlo


¿Qué hay de usar la clase Process desde el código Java? Y luego leyendo la salida del comando.

Process p = Runtime.getRuntime().exec("wc -l " + yourfilename); p.waitFor(); BufferedReader b = new BufferedReader(new InputStreamReader(p.getInputStream())); String line = ""; int lineCount = 0; while ((line = b.readLine()) != null) { System.out.println(line); lineCount = Integer.parseInt(line); }

Necesito probarlo sin embargo. Publicaré los resultados.


Código optimizado para archivos de varias líneas que no tienen caracteres de nueva línea (''/ n'') en EOF.

/** * * @param filename * @return * @throws IOException */ public static int countLines(String filename) throws IOException { int count = 0; boolean empty = true; FileInputStream fis = null; InputStream is = null; try { fis = new FileInputStream(filename); is = new BufferedInputStream(fis); byte[] c = new byte[1024]; int readChars = 0; boolean isLine = false; while ((readChars = is.read(c)) != -1) { empty = false; for (int i = 0; i < readChars; ++i) { if ( c[i] == ''/n'' ) { isLine = false; ++count; }else if(!isLine && c[i] != ''/n'' && c[i] != ''/r''){ //Case to handle line count where no New Line character present at EOF isLine = true; } } } if(isLine){ ++count; } }catch(IOException e){ e.printStackTrace(); }finally { if(is != null){ is.close(); } if(fis != null){ fis.close(); } } LOG.info("count: "+count); return (count == 0 && !empty) ? 1 : count; }


Con java-8 , puedes usar streams:

try (Stream<String> lines = Files.lines(path, Charset.defaultCharset())) { long numOfLines = lines.count(); ... }


En sistemas basados ​​en Unix, use el comando wc en la línea de comandos.


Esta es la versión más rápida que he encontrado hasta ahora, aproximadamente 6 veces más rápida que readLines. En un archivo de registro de 150MB esto toma 0.35 segundos, contra 2.40 segundos cuando se usa readLines (). Sólo por diversión, el comando linux ''wc -l tarda 0.15 segundos.

public static int countLines(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(); } }

EDITADO, 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 solución LineNumberReader 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 que se necesitan algunas ejecuciones hasta que el optimizador haga un trabajo decente. He jugado un poco con el código y he producido una nueva versión que es siempre 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(); } }

Benchmark resulsa 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 countLines tiene algunos valores atípicos, y countLinesNew no tiene ninguno y parece ser un poco más rápido. LineNumberReader es claramente más lento.


He implementado otra solución al problema, la encontré más eficiente al contar filas:

try ( FileReader input = new FileReader("input.txt"); LineNumberReader count = new LineNumberReader(input); ) { while (count.skip(Long.MAX_VALUE) > 0) { // Loop just in case the file is > Long.MAX_VALUE or skip() decides to not read the entire file } result = count.getLineNumber() + 1; // +1 because line index starts at 0 }


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, lo que le da una longitud promedio de una línea y luego obtener el tamaño del archivo y dividirlo con avg. Longitud pero eso no será exacto.


La respuesta aceptada tiene un error de apagado 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 de FinalWithoutNewLine son un desperdicio para todo menos la lectura final, pero deben ser triviales en comparación con la función general.

public int count(String filename) throws IOException { InputStream is = new BufferedInputStream(new FileInputStream(filename)); try { byte[] c = new byte[1024]; int count = 0; int readChars = 0; boolean endsWithoutNewLine = false; while ((readChars = is.read(c)) != -1) { for (int i = 0; i < readChars; ++i) { if (c[i] == ''/n'') ++count; } endsWithoutNewLine = (c[readChars - 1] != ''/n''); } if(endsWithoutNewLine) { ++count; } return count; } finally { is.close(); } }


La respuesta con el método count () anterior me dio errores de línea 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í:

public int countLines(String filename) throws IOException { LineNumberReader reader = new LineNumberReader(new FileReader(filename)); int cnt = 0; String lineRead = ""; while ((lineRead = reader.readLine()) != null) {} cnt = reader.getLineNumber(); reader.close(); return cnt; }


Llegué a la conclusión de que el método de conteo de nuevas líneas de wc -l : s 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 al agregar una al recuento de líneas, arrojó resultados no intuitivos en los archivos donde la última línea termina con una nueva línea.

Por eso hice un algo que se maneja de la siguiente manera:

@Test public void empty() throws IOException { assertEquals(0, count("")); } @Test public void singleNewline() throws IOException { assertEquals(1, count("/n")); } @Test public void dataWithoutNewline() throws IOException { assertEquals(1, count("one")); } @Test public void oneCompleteLine() throws IOException { assertEquals(1, count("one/n")); } @Test public void twoCompleteLines() throws IOException { assertEquals(2, count("one/ntwo/n")); } @Test public void twoLinesWithoutNewlineAtEnd() throws IOException { assertEquals(2, count("one/ntwo")); } @Test public void aFewLines() throws IOException { assertEquals(5, count("one/ntwo/nthree/nfour/nfive/n")); }

Y se parece a esto:

static long countLines(InputStream is) throws IOException { try(LineNumberReader lnr = new LineNumberReader(new InputStreamReader(is))) { char[] buf = new char[8192]; int n, previousN = -1; //Read will return at least one byte, no need to buffer more while((n = lnr.read(buf)) != -1) { previousN = n; } int ln = lnr.getLineNumber(); if (previousN == -1) { //No data read at all, i.e file was empty return 0; } else { char lastChar = buf[previousN - 1]; if (lastChar == ''/n'' || lastChar == ''/r'') { //Ending with newline, deduct one return ln; } } //normal case, return line number + 1 return ln + 1; } }

Si quieres resultados intuitivos, puedes usar esto. Si solo desea la compatibilidad con wc -l , use la solución @ er.vikas, pero no agregue una al resultado y vuelva a intentar el salto:

try(LineNumberReader lnr = new LineNumberReader(new FileReader(new File("File1")))) { while(lnr.skip(Long.MAX_VALUE) > 0){}; return lnr.getLineNumber(); }


Probé los métodos anteriores para el recuento de líneas y aquí están mis observaciones para diferentes métodos según lo probado en mi sistema.

Tamaño del archivo: 1.6 Gb Métodos:

  1. Utilizando escáner : 35 s aprox
  2. Utilizando BufferedReader : 5s aprox
  3. Utilizando Java 8 : 5s aprox.
  4. Usando LineNumberReader : 5s aprox

Además, el enfoque de Java8 parece bastante útil: Files.lines (Paths.get (filePath), Charset.defaultCharset ()). Count () [Tipo de devolución: largo]


Sé que esta es una pregunta antigua, pero la solución aceptada no coincidía con lo que necesitaba que hiciera. Por lo tanto, lo refiné para aceptar varios terminadores de línea (en lugar de solo para el salto de línea) y para usar una codificación de caracteres especificada (en lugar de ISO-8859- n ). Todo en un método (refactor, según corresponda):

public static long getLinesCount(String fileName, String encodingName) throws IOException { long linesCount = 0; File file = new File(fileName); FileInputStream fileIn = new FileInputStream(file); try { Charset encoding = Charset.forName(encodingName); Reader fileReader = new InputStreamReader(fileIn, encoding); int bufferSize = 4096; Reader reader = new BufferedReader(fileReader, bufferSize); char[] buffer = new char[bufferSize]; int prevChar = -1; int readCount = reader.read(buffer); while (readCount != -1) { for (int i = 0; i < readCount; i++) { int nextChar = buffer[i]; switch (nextChar) { case ''/r'': { // The current line is terminated by a carriage return or by a carriage return immediately followed by a line feed. linesCount++; break; } case ''/n'': { if (prevChar == ''/r'') { // The current line is terminated by a carriage return immediately followed by a line feed. // The line has already been counted. } else { // The current line is terminated by a line feed. linesCount++; } break; } } prevChar = nextChar; } readCount = reader.read(buffer); } if (prevCh != -1) { switch (prevCh) { case ''/r'': case ''/n'': { // The last line is terminated by a line terminator. // The last line has already been counted. break; } default: { // The last line is terminated by end-of-file. linesCount++; } } } } finally { fileIn.close(); } return linesCount; }

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 sincronización en Java son notoriamente poco confiables).


Si no tiene ninguna estructura de índice, no podrá evitar leer el archivo completo. Pero puede optimizarlo evitando leerlo línea por línea y usar una expresión regular para hacer coincidir todos los terminadores de línea.


Una forma sencilla de usar el escáner

static void lineCounter (String path) throws IOException { int lineCount = 0, commentsCount = 0; Scanner input = new Scanner(new File(path)); while (input.hasNextLine()) { String data = input.nextLine(); if (data.startsWith("//")) commentsCount++; lineCount++; } System.out.println("Line Count: " + lineCount + "/t Comments Count: " + commentsCount); }


si usas esto

public int countLines(String filename) throws IOException { LineNumberReader reader = new LineNumberReader(new FileReader(filename)); int cnt = 0; String lineRead = ""; while ((lineRead = reader.readLine()) != null) {} cnt = reader.getLineNumber(); reader.close(); return cnt; }

no se puede ejecutar en filas numéricas grandes, le gustan las filas de 100K, porque el retorno de reader.getLineNumber es int. necesita un tipo largo de datos para procesar las filas máximas ...


/** * Count file rows. * * @param file file * @return file row count * @throws IOException */ public static long getLineCount(File file) throws IOException { try (Stream<String> lines = Files.lines(file.toPath())) { return lines.count(); } }

Probado en JDK8_u31. Pero, de hecho, el rendimiento es lento en comparación con este método:

/** * Count file rows. * * @param file file * @return file row count * @throws IOException */ public static long getLineCount(File file) throws IOException { try (BufferedInputStream is = new BufferedInputStream(new FileInputStream(file), 1024)) { byte[] c = new byte[1024]; boolean empty = true, lastEmpty = false; long count = 0; int read; while ((read = is.read(c)) != -1) { for (int i = 0; i < read; i++) { if (c[i] == ''/n'') { count++; lastEmpty = true; } else if (lastEmpty) { lastEmpty = false; } } empty = false; } if (!empty) { if (count == 0) { count = 1; } else if (!lastEmpty) { count++; } } return count; } }

Probado y muy rápido.