Preciso ler um arquivo de texto grande de cerca de 5-6 GB, linha por linha, usando Java.
Como posso fazer isso rapidamente?
java
performance
file-io
io
garbage-collection
manoj singh
fonte
fonte
Respostas:
Um padrão comum é usar
Você pode ler os dados mais rapidamente se considerar que não há codificação de caracteres. por exemplo, ASCII-7, mas não fará muita diferença. É altamente provável que o que você faz com os dados demore muito mais.
EDIT: Um padrão menos comum de usar que evita o escopo de
line
vazamento.ATUALIZAÇÃO: No Java 8 você pode fazer
NOTA: Você deve colocar o Stream em um bloco try-with-resource para garantir que o método #close seja chamado, caso contrário, o identificador de arquivo subjacente nunca será fechado até que o GC o faça muito mais tarde.
fonte
for(String line = br.readLine(); line != null; line = br.readLine())
, no Java 8 você pode fazer otry( Stream<String> lines = Files.lines(...) ){ for( String line : (Iterable<String>) lines::iterator ) { ... } }
que é difícil não odiar.Veja este blog:
fonte
DataInputStream
, e o fluxo errado é fechado. Nada de errado com o Tutorial Java, e não há necessidade de citar lixo arbitrário da Internet de terceiros como este.Quando o Java 8 for lançado (março de 2014), você poderá usar fluxos:
Imprimindo todas as linhas no arquivo:
fonte
StandardCharsets.UTF_8
, useStream<String>
por concisão e evite usáforEach()
-lo, especialmente aforEachOrdered()
menos que haja um motivo.forEach(this::process)
, mas fica feio se você escrever blocos de código como lambdas dentroforEach()
.forEachOrdered
executar em ordem. Esteja ciente de que não será possível paralelizar o fluxo nesse caso, embora eu tenha descoberto que a paralelização não é ativada, a menos que o arquivo tenha milhares de linhas.Aqui está uma amostra com tratamento completo de erros e especificação de conjunto de caracteres de suporte para pré-Java 7. Com o Java 7, você pode usar a sintaxe try-with-resources, o que torna o código mais limpo.
Se você deseja apenas o conjunto de caracteres padrão, pode pular o InputStream e usar o FileReader.
Aqui está a versão Groovy, com manipulação completa de erros:
fonte
ByteArrayInputStream
literal alimentado por uma string tem a ver com a leitura de um arquivo de texto grande?No Java 8, você pode fazer:
Algumas notas: O fluxo retornado por
Files.lines
(diferente da maioria dos fluxos) precisa ser fechado. Pelas razões mencionadas aqui , evito usarforEach()
. O código estranho(Iterable<String>) lines::iterator
lança um fluxo em um iterável.fonte
Iterable
esse código, é definitivamente feio, embora útil. Ele precisa de um elenco (ou seja(Iterable<String>)
) para funcionar.for(String line : (Iterable<String>) lines.skip(1)::iterator)
Stream
recursos, usandoFiles.newBufferedReader
, em vez deFiles.lines
e repetidamente chamadoreadLine()
aténull
em vez de usar construções como(Iterable<String>) lines::iterator
parece ser muito mais simples ...O que você pode fazer é digitalizar o texto inteiro usando o Scanner e percorrer o texto linha por linha. Obviamente, você deve importar o seguinte:
O scanner basicamente digitaliza todo o texto. O loop while é usado para percorrer o texto inteiro.
A
.hasNextLine()
função é um booleano que retorna true se ainda houver mais linhas no texto. A.nextLine()
função fornece uma linha inteira como uma String, que você pode usar da maneira que desejar. TenteSystem.out.println(line)
imprimir o texto.Nota: .txt é o texto do tipo de arquivo.
fonte
BufferedReader.readLine()
, e ele pediu o método com melhor desempenho.O FileReader não permitirá que você especifique a codificação, use-a
InputStreamReader
se precisar especificá-la:Se você importou esse arquivo do Windows, ele pode ter codificação ANSI (Cp1252), portanto, você deve especificar a codificação.
fonte
Documentei e testei 10 maneiras diferentes de ler um arquivo em Java e, em seguida, executei-os um contra o outro, fazendo-os ler em arquivos de teste de 1 KB a 1 GB. Aqui estão os três métodos de leitura de arquivos mais rápidos para ler um arquivo de teste de 1 GB.
Observe que, ao executar os testes de desempenho, não produzi nada para o console, pois isso realmente atrasaria o teste. Eu só queria testar a velocidade de leitura bruta.
1) java.nio.file.Files.readAllBytes ()
Testado em Java 7, 8, 9. Esse foi o método mais rápido. A leitura de um arquivo de 1 GB consistia em pouco menos de 1 segundo.
2) java.nio.file.Files.lines ()
Isso foi testado com sucesso no Java 8 e 9, mas não funcionará no Java 7 devido à falta de suporte para expressões lambda. Demorou cerca de 3,5 segundos para ler um arquivo de 1 GB, o que o colocou em segundo lugar na leitura de arquivos maiores.
3) BufferedReader
Testado para funcionar em Java 7, 8, 9. Demorou cerca de 4,5 segundos para ler em um arquivo de teste de 1 GB.
Você pode encontrar as classificações completas para todos os 10 métodos de leitura de arquivos aqui .
fonte
System.out.print/println()
aqui; você também está assumindo que o arquivo caberá na memória nos dois primeiros casos.No Java 7:
fonte
StandardCharsets.UTF_8
para evitar a exceção verificada noCharset.forName("UTF-8")
No Java 8, também há uma alternativa ao uso
Files.lines()
. Se a sua fonte de entrada não for um arquivo, mas algo mais abstrato como umReader
ou umInputStream
, você pode transmitir as linhas através do métodoBufferedReader
slines()
.Por exemplo:
chamará
processLine()
cada linha de entrada lida peloBufferedReader
.fonte
Para ler um arquivo com Java 8
fonte
Você pode usar a classe Scanner
fonte
Scanner
é bom, mas esta resposta não inclui o código completo para usá-lo corretamente.BufferedReader.readLine()
seja certamente várias vezes mais rápido. Se você pensa o contrário, forneça seus motivos.Você precisa usar o
readLine()
métodoclass BufferedReader
. Crie um novo objeto dessa classe e opere esse método nele e salve-o em uma string.Javadoc BufferReader
fonte
A maneira clara de conseguir isso,
Por exemplo:
Se você tem
dataFile.txt
no seu diretório atualA saída como abaixo,
fonte
Java 9:
fonte
System.getProperty("os.name").equals("Linux")
==
!Funciona para mim. Espero que também ajude você.
fonte
Você pode usar fluxos para fazer isso com mais precisão:
fonte
Eu costumo fazer a rotina de leitura direta:
fonte
Você pode usar este código:
fonte
Ao usar o pacote org.apache.commons.io , ele deu mais desempenho, especialmente no código legado que usa Java 6 e abaixo.
O Java 7 tem uma API melhor, com menos manipulação de exceções e métodos mais úteis:
Maven
fonte
Você também pode usar o Apache Commons IO :
fonte
FileUtils.readLines(file)
é um método obsoleto. Além disso, o método chamaIOUtils.readLines
, que usa um BufferedReader e ArrayList. Este não é um método linha por linha, e certamente não seria prático para a leitura de vários GB.