Estou com um problema para ler um arquivo texto com cerca de 800MB.
Estou usando a seguinte rotina:
BufferedReader br = new BufferedReader(new FileReader(file));
while ((linha = br.readLine()) != null) {
// aqui faço umas verificações com a pedaços da linha
// faço alguns substrings e vejo se o valor está em determinado padrão
}
Não consigo rodar isso, antes de chegar na metade do arquivo dá um Java Heap Space.
Porém não posso simplesmente aumentar a memória das configurações do glassfish porque a aplicação vai precisar suportar qualquer tamanho de arquivo.
O BufferedReader vai lendo as linhas do arquivo texto e guarda na memória ?
Existe uma forma mais eficiente de fazer essa leitura ?
Vou fazer um pequeno parêntese, que não tem absolutamente nada a ver com o problema que você está tendo.
Digamos que você leia uma string de 1.000.000 caracteres e pegue dela apenas uma substring de 100 caracteres.
String s = ...;
String pequena = s.substring (100, 200);
s = null;
Quanto espaço, após fazer “s = null”, vai ser ocupado na memória?
a) 100 caracteres - quando você cria a nova string, copia os caracteres da string antiga e a referência à string grande se perde.
b) 1M caracteres - quando você cria a nova string, ela simplesmente é um ponteiro para o início e o fim dos caracteres da string antiga. Então, mesmo você removendo a referência à string antiga, o array de caracteres que é contido pela string antiga não se perde.
Por incrível que pareça, a resposta é “b)”.
É que normalmente isso não ocorre, mas é bom você ficar esperto.
Se tal caso se repetir muito, você até pode tentar algo como:
String pequena = new String (s.substring (100, 200).toCharArray());
Basicamente essas verificações que faço são do tipo:
while ((linha = br.readLine()) != null) {
valor = pegaPosicao(linha, 22, 141);
if (valor.equals("")) {
escreveCritica("Erro na linha " + iLinha + ". Nome do Beneficiário em Branco", true);
setErros(getErros() + 1);
}
// cerca de 20 blocos como esse
}
public String pegaPosicao(String valor, Integer posInicial, Integer posFinal) {
return valor.substring(posInicial - 1, posFinal).trim();
}
public void escreveCritica(String conteudo, Boolean adiciona) throws IOException {
PrintWriter out = new PrintWriter(new FileWriter(getCritica(), adiciona));
out.println(conteudo);
out.close();
out = null;
}
Já testei se o problema era no método escreveCritica comentando tudo que estava lá dentro, mas o erro persistiu.
Então deveria fazer algo como:
valor = new String (pegaPosicao(linha, 22, 141).toCharArray());
Estou declarando essa String antes do while(), deveria declarar dentro ?
Obrigado entanglement, coloquei pra rodar de novo e está em um ponto que está usando 300MB de memória, sendo que antes das alterações já estaria com mais de 600MB
Só corrigindo uma coisa no método:
public String pegaPosicao(String valor, Integer posInicial, Integer posFinal) {
String s = valor.substring (posInicial - 1, posFinal).trim();
if (s.isEmpty()) return emptyString;
else return new String (s.toCharArray());
}
no que vc colocou estava retornando valor.toCharArray()