Gerando arquivo texto gigantesco

16 respostas
R

Alguém aí já teve que gerar arquivos muito grandes?(500/600Mb)
Até agora só havia gerado coisas pequenas, e agora com a quantidade de dados, tô tomando uma surra.
Eu retorno do banco algumas milhares de linhas, e vou duplicando essas linhas dentro de um arquivo texto. Mas dependendo da quantidade de registros que retorno, ele estoura a memória do servidor(1Gb). Tem alguma forma de eu não deixar este arquivo carregado na memória? Ir adicionando somente ao final dele cada linha que retorno do banco.

Grato

16 Respostas

L

Se você usar um BufferedWriter/FileWriter não tem galho algum. Você não tá escrevendo em um String(Writer|Buffer) e depois pro disco né?

J
Porque você não tenta dimensionar o tamanho médio do arquivo OU quantos registros você vai colocar no arquivo(em média). Em posse dessas informações, faz um loop, grava um punhado no arquivo, fecha ele, elege o método pro gc. E vai fazendo isso até o final de registros. Acho que vai ficar um pouco trabalhoso, mas já tive que fazer isso com VB há muito tempo atrás e funcionou.
R

To nada, tô fazendo um ‘BufferedWriter.write(registro)’ direto, mas mesmo assim tá estourando a memória do servidor. Creio que deve ser por causa da quantidade de registros (22000 * N * 4 - sendo que n pode variar de 2 a 100)

O problema é que esse arquivo é pra receita federal, tem que ser um arquivo só. Creio que na hora de ler todos os arquivos para montar um só, eu cairia no mesmo problema.

C

Que eu saiba se vc usar o BufferedWriter/FileWriter ele não vai ficar guardando tudo na memória.

É possível que o que está estourando a memória é a consulta retornada e não o arquivo. Daí vc vai ter que fazer paginação ou coisa do gênero.

J

Rafael Nunes:
O problema é que esse arquivo é pra receita federal, tem que ser um arquivo só. Creio que na hora de ler todos os arquivos para montar um só, eu cairia no mesmo problema.
Acho que a gente teve um pequeno problema de comunicação
O que eu estava tentando lhe dizer é: colocar, por exemplo, 5 mil em 5 mil registros por vez, no mesmo arquivo, porque daí acho que o gc iria trabalhar, já que houve uma pequena pausa.
Ou então, sei lá, tenta criar uma thread que faça isso.

R

ciczan:
Que eu saiba se vc usar o BufferedWriter/FileWriter ele não vai ficar guardando tudo na memória.

É possível que o que está estourando a memória é a consulta retornada e não o arquivo. Daí vc vai ter que fazer paginação ou coisa do gênero.

Tô usando um framework da empresa aqui pra manipular o resultset, depois que o louds falou fui dar uma olhada, e ele retorna uma String para cada coluna. Deve ser o excesso de objetos criados.

C

Uma idéia é vc fazer várias consultas. Tipo se é pro ano inteiro, vc faz uma pra cada mês, tomando o cuidado para deixar o resultset “garbage colectable”.

Ainda acho que o problema não é com o arquivo.

L

O problema não é o excesso de objetos criados, mas sim quantos você mantem ao mesmo tempo em memória.

Esse teu result-set vem com 500mil registros de uma vez só? O driver faz paginaçã ou coloca tudo em memória de uma única vez?

R

louds:
O problema não é o excesso de objetos criados, mas sim quantos você mantem ao mesmo tempo em memória.

Esse teu result-set vem com 500mil registros de uma vez só? O driver faz paginaçã ou coloca tudo em memória de uma única vez?

Tudo de uma vez ele retorna. Mas o problema é que ele tá retornando os registros, é no momento que eu jogo eles para o arquivo que estoura a memória.

Edit: Dúvida besta, se eu paginar isso, na execução ele por exemplo retorna 200 mil registros, quando eu retornar o restante da paginação ele não ocuparia mais espaço em memória? Ou ele vai sobrepor o resultado anterior?

O

Você está indicando que arquivo é para append na abertura ?

FileOutputStream appendedFile = new FileOutputStream
		("arquivo", true);

O segundo parâmetro indica que é para append.

L

Rafael Nunes:

Tudo de uma vez ele retorna. Mas o problema é que ele tá retornando os registros, é no momento que eu jogo eles para o arquivo que estoura a memória.

Sim, vai ser mesmo quando você ler o resultset que vai explodir tudo, já que ele vai manter os 500mil em memória. Meio obvio isso.

O problema não é com a parte de I/O do java, pq tem código meu fazendo multiway-merge com arquivos de vários gigas e nem precisa de -Xmx para executar.

R

louds:
Sim, vai ser mesmo quando você ler o resultset que vai explodir tudo, já que ele vai manter os 500mil em memória. Meio obvio isso.

Taí algo que eu não sabia, que só no primeiro acesso que ele ‘explode’, mas bem estranho é que debugando aqui, ele estoura a memória no meio da gravação de dados, depois de gravar uma boa parte.
Vou tentar usar o Resulset direto mesmo ver que zica dá.

T

Se não me engano, quando você cria um BufferedWriter, são alocados apenas 8KB para um buffer interno (você pode usar um segundo parâmetro que possibilita especificar um buffer maior.)

Então não é o problema do BufferedWriter, e sim de sua consulta.

(Se você usar a consulta de modo que os dados não sejam retidos na memória, ou seja, abrir um Forward-Only Cursor, então não deveria haver problemas).

Uma forma de você ver que troço está gastando memória é rodar seu programa com o Mustang e usar o programa jmap com a opção -dump, e usar o jhat para mostrar (usando uma interface web bem simples) quais são os objetos que ocupam mais memória. Mas pelo jeito é só alterar o jeito de você abrir seu ResultSet.

O

tente usar a propriedade setFetchSize(int rows) do resultset.

R

Fiz diretamente com ResultSet e foi, sei lá como diabos o framework tava tratando isso.
Bregado pela força.

T

Frameworks são legais mas sempre há aqueles “casos limite”. Esse seu caso é um deles - o cara que escreveu o framework provavelmente deve ter pensado em CRUD, não em relatórios gigantes.

Criado 5 de junho de 2006
Ultima resposta 5 de jun. de 2006
Respostas 16
Participantes 6