Esta é a versão mais rápida que encontrei até agora, cerca de 6 vezes mais rápida que a readLines. Em um arquivo de log de 150 MB, leva 0,35 segundos, contra 2,40 segundos ao usar readLines (). Apenas por diversão, o comando linux 'wc -l leva 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();
}
}
EDIT, 9 anos e meio depois: praticamente não tenho experiência em java, mas, de qualquer forma, tentei comparar esse código com a LineNumberReader
solução abaixo, pois me incomodava o fato de ninguém fazer isso. Parece que, especialmente para arquivos grandes, minha solução é mais rápida. Embora pareça levar algumas execuções até que o otimizador faça um trabalho decente. Eu brinquei um pouco com o código e produzi uma nova versão que é consistentemente mais 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();
}
}
O resultado de referência resulta em um arquivo de texto de 1,3 GB, eixo y em segundos. Eu executei 100 execuções com o mesmo arquivo e medi cada execução com System.nanoTime()
. Você pode ver que countLinesOld
possui alguns valores discrepantes e countLinesNew
nenhum, e embora seja um pouco mais rápido, a diferença é estatisticamente significativa. LineNumberReader
é claramente mais lento.
Eu implementei outra solução para o problema, achei mais eficiente na contagem de linhas:
fonte
LineNumberReader
OlineNumber
campo de é um número inteiro ... Não será apenas agrupado para arquivos maiores que Integer.MAX_VALUE? Por que se preocupar em pular um longo tempo aqui?wc -l
conta o número de caracteres de nova linha no arquivo. Isso funciona, pois todas as linhas são finalizadas com uma nova linha, incluindo a linha final em um arquivo. Toda linha tem um caractere de nova linha, incluindo as linhas vazias, portanto, o número de linhas nova = = número de linhas em um arquivo. Agora, alineNumber
variável inFileNumberReader
também representa o número de caracteres de nova linha vistos. Começa em zero, antes que qualquer nova linha seja encontrada e aumenta a cada caractere de nova linha visto. Portanto, não adicione um ao número da linha, por favor.wc -l
também informa esse tipo de arquivo. Veja também stackoverflow.com/questions/729692/…wc -l
retornaria 1. Concluí que todos os métodos têm falhas e implementei um com base em como gostaria que ele se comportasse. Veja minha outra resposta aqui.A resposta aceita tem um erro de um por um para arquivos com várias linhas que não terminam em nova linha. Um arquivo de uma linha que termina sem uma nova linha retornará 1, mas um arquivo de duas linhas que termina sem uma nova linha retornará 1 também. Aqui está uma implementação da solução aceita que corrige isso. As verificações endsWithoutNewLine são um desperdício para tudo, exceto a leitura final, mas devem ser triviais em termos de tempo em comparação com a função geral.
fonte
Com java-8, você pode usar fluxos:
fonte
A resposta com o método count () acima me deu erros de linha se um arquivo não tivesse uma nova linha no final do arquivo - ele falhou ao contar a última linha do arquivo.
Este método funciona melhor para mim:
fonte
cnt
.Sei que essa é uma pergunta antiga, mas a solução aceita não corresponde exatamente ao que eu precisava. Portanto, refinei-o para aceitar vários terminadores de linha (em vez de apenas feed de linha) e usar uma codificação de caracteres especificada (em vez da ISO-8859- n ). Tudo em um método (refatorar conforme apropriado):
Essa solução é comparável em velocidade à solução aceita, cerca de 4% mais lenta em meus testes (embora os testes de temporização em Java sejam notoriamente não confiáveis).
fonte
Testei os métodos acima para contar linhas e aqui estão minhas observações para diferentes métodos testados no meu sistema
Tamanho do arquivo: 1.6 Gb Métodos:
Além disso, a abordagem Java8 parece bastante útil:
fonte
Testado em JDK8_u31. Mas, na verdade, o desempenho é lento em comparação com este método:
Testado e muito rápido.
fonte
Stream<String> - Time consumed: 122796351 Stream<String> - Num lines: 109808 Method - Time consumed: 12838000 Method - Num lines: 1
E o número de linhas também está errado tambémBufferedInputStream
quando quiser ler o seu próprio buffer. Além disso, mesmo que seu método possa ter uma pequena vantagem de desempenho, ele perde flexibilidade, pois não suporta mais\r
terminadores de linha única (MacOS antigo) e não suporta todas as codificações.Uma maneira direta de usar o Scanner
fonte
Concluí que
wc -l
: o método de contar novas linhas é bom, mas retorna resultados não intuitivos em arquivos nos quais a última linha não termina com uma nova linha.E a solução @ er.vikas baseada em LineNumberReader, mas a adição de uma na contagem de linhas retornou resultados não intuitivos em arquivos nos quais a última linha termina com nova linha.
Portanto, fiz um algo que lida com o seguinte:
E fica assim:
Se você deseja resultados intuitivos, pode usar isso. Se você deseja apenas
wc -l
compatibilidade, use a solução @ er.vikas, mas não adicione uma ao resultado e tente pular novamente:fonte
Que tal usar a classe Process a partir do código Java? E então lendo a saída do comando.
Precisa tentar embora. Irá publicar os resultados.
fonte
Se você não possui nenhuma estrutura de índice, não contorna a leitura do arquivo completo. Mas você pode otimizá-lo, evitando lê-lo linha por linha e usar um regex para corresponder a todos os terminadores de linha.
fonte
Esta solução divertida funciona realmente muito bem!
fonte
Em sistemas baseados em Unix, use o
wc
comando na linha de comandos.fonte
A única maneira de saber quantas linhas existem no arquivo é contá-las. Obviamente, você pode criar uma métrica a partir dos seus dados, fornecendo um comprimento médio de uma linha e, em seguida, obter o tamanho do arquivo e dividi-lo com o valor médio. comprimento, mas isso não será preciso.
fonte
Melhor código otimizado para arquivos de várias linhas sem caracteres de nova linha ('\ n') no EOF.
fonte
Scanner com regex:
Ainda não cronometrei.
fonte
se você usar isso
você não pode executar linhas grandes, gosta de 100 mil linhas, porque o retorno de reader.getLineNumber é int. você precisa de um tipo longo de dados para processar o máximo de linhas.
fonte
int
pode armazenar valores de até aproximadamente 2 bilhões. Se você estiver carregando um arquivo com mais de 2 bilhões de linhas, há um problema de estouro. Dito isto, se você estiver carregando um arquivo de texto não indexado com mais de dois bilhões de linhas, provavelmente terá outros problemas.