Como ler um arquivo grande com eficiência com Java
1. Visão geral
Este tutorial mostraráhow to read all the lines from a large file in Java de maneira eficiente.
Este artigo faz parte dethe “Java – Back to Basic” tutorial aqui no exemplo.
Leitura adicional:
Java - Escreva um InputStream em um arquivo
Como gravar um InputStream em um arquivo - usando Java, Guava e a biblioteca do Commons IO.
Java - Converter arquivo para InputStream
Como abrir um InputStream a partir de um arquivo Java - usando Java simples, Guava e a biblioteca Apache Commons IO.
Java - Ler do arquivo
Leia o conteúdo de um arquivo em Java - usando qualquer um destes: BufferedReader, Scanner, StreamTokenizer, DataInputStream, SequenceInputStream, FileChannel, etc.
2. Leitura na memória
A maneira padrão de ler as linhas do arquivo está na memória - o Guava e o Apache Commons IO fornecem uma maneira rápida de fazer exatamente isso:
Files.readLines(new File(path), Charsets.UTF_8);
FileUtils.readLines(new File(path));
O problema com essa abordagem é que todas as linhas do arquivo são mantidas na memória - o que levará rapidamente aOutOfMemoryError se o arquivo for grande o suficiente.
Por exemplo -reading a ~1Gb file:
@Test
public void givenUsingGuava_whenIteratingAFile_thenWorks() throws IOException {
String path = ...
Files.readLines(new File(path), Charsets.UTF_8);
}
Isso começa com uma pequena quantidade de memória sendo consumida:(~0 Mb consumed)
[main] INFO org.example.java.CoreJavaIoUnitTest - Total Memory: 128 Mb
[main] INFO org.example.java.CoreJavaIoUnitTest - Free Memory: 116 Mb
Porém,after the full file has been processed, temos no final:(~2 Gb consumed)
[main] INFO org.example.java.CoreJavaIoUnitTest - Total Memory: 2666 Mb
[main] INFO org.example.java.CoreJavaIoUnitTest - Free Memory: 490 Mb
O que significa que cerca de 2,1 Gb de memória são consumidos pelo processo - o motivo é simples - as linhas do arquivo estão sendo armazenadas na memória agora.
Deve ser óbvio neste ponto quekeeping in memory the contents of the file will quickly exhaust the available memory - independentemente de quanto isso realmente seja.
Além do mais,we usually don’t need all of the lines in the file in memory at once - em vez disso, só precisamos ser capazes de iterar em cada um, fazer algum processamento e jogá-lo fora. Então, isso é exatamente o que vamos fazer - iterar através das linhas sem manter na memória.
3. Streaming por meio do arquivo
Vamos agora olhar para uma solução - vamos usar umjava.util.Scanner para percorrer o conteúdo do arquivo e recuperar as linhas em série, uma por uma:
FileInputStream inputStream = null;
Scanner sc = null;
try {
inputStream = new FileInputStream(path);
sc = new Scanner(inputStream, "UTF-8");
while (sc.hasNextLine()) {
String line = sc.nextLine();
// System.out.println(line);
}
// note that Scanner suppresses exceptions
if (sc.ioException() != null) {
throw sc.ioException();
}
} finally {
if (inputStream != null) {
inputStream.close();
}
if (sc != null) {
sc.close();
}
}
Esta solução irá iterar por todas as linhas do arquivo - permitindo o processamento de cada linha - sem manter referências a elas - e em conclusão,without keeping them in memory:(~150 Mb consumed)
[main] INFO org.example.java.CoreJavaIoUnitTest - Total Memory: 763 Mb
[main] INFO org.example.java.CoreJavaIoUnitTest - Free Memory: 605 Mb
4. Streaming com Apache Commons IO
O mesmo pode ser obtido usando a biblioteca Commons IO, usandothe custom LineIterator fornecido pela biblioteca:
LineIterator it = FileUtils.lineIterator(theFile, "UTF-8");
try {
while (it.hasNext()) {
String line = it.nextLine();
// do something with line
}
} finally {
LineIterator.closeQuietly(it);
}
Como o arquivo inteiro não está totalmente na memória, isso também resultará empretty conservative memory consumption numbers:(~150 Mb consumed)
[main] INFO o.b.java.CoreJavaIoIntegrationTest - Total Memory: 752 Mb
[main] INFO o.b.java.CoreJavaIoIntegrationTest - Free Memory: 564 Mb
5. Conclusão
Este artigo rápido mostra comoprocess lines in a large file without iteratively, without exhausting the available memory - o que é bastante útil ao trabalhar com esses arquivos grandes.
A implementação de todos esses exemplos e trechos de códigocan be found in our GitHub project - este é um projeto baseado em Maven, portanto, deve ser fácil de importar e executar como está.