Lendo arquivos gigantes

12 respostas
M

estou com um probleminha, tenho um arquivo de 8gb. de informações…

preciso ler este arquivo e inserir no banco de dados estou utilizando da seguinte forma

como o arquivo é grande, no inicio a rotina roda na boa, mas conforme vai processando, vai consumindo memória…

tem como limpara o BufferedReader ??? ou há outra forma de ler arquivos gigantescos???

12 Respostas

maquiavelbona

Tente fazer com Java NIO:
http://guj.com.br/java.tutorial.artigo.118.1.guj

Até!

T

O que gasta memória é o tal “parse” e “processo da String”.
O que é que você faz?
Cria um arraylist das linhas do arquivo?
Ordena-o no braço?
Se possível, conserve o mínimo de linhas em memória - mas não sei o que você faz com as linhas.
NIO não resolve seu problema de memória - na verdade pode agravá-lo.

T

O buffer criado por BufferedReader é relativamente pequeno - 8KB - portanto não deve ser ele o culpado pelos seus problemas.

M

dou um parce da string e faço um insert no banco de dados…


int inicio = 0;
if (linha.indexOf("GET") &gt -1)

inicio = linha.indexOf("GET") + 4;
			
		else
			inicio = linha.indexOf("POST") + 5;
		
		String auxi = linha.substring(inicio);
		String url = auxi.substring(0,auxi.indexOf("\""));
		
		PreparedStatement ps = con.prepareStatement(sql); 
		ps.setString(1, url);
		ps.execute();</blockquote>

T

Se você precisa inserir muitas coisas no banco de dados de uma vez, o indicado é criar um outro arquivo-texto, apropriado para o seu banco de dados fazer um “bulk insert” ou “bulk load”. Aí você chama o comando adequado que seu banco.
É muito mais rápido e eficiente que dar um milhão de comandos INSERT ou UPDATE no seu banco.

Por exemplo, no Oracle você pode usar o SQL*Loader para importar esses arquivos gigantes.

dudaskank

mark_domi:
dou um parce da string e faço um insert no banco de dados…


int inicio = 0;
if (linha.indexOf("GET") &gt -1)

inicio = linha.indexOf("GET") + 4;
			
		else
			inicio = linha.indexOf("POST") + 5;
		
		String auxi = linha.substring(inicio);
		String url = auxi.substring(0,auxi.indexOf("\""));
		
		PreparedStatement ps = con.prepareStatement(sql); 
		ps.setString(1, url);
		ps.execute();</blockquote>

Além do que o thingol disse, você deve criar o prepared statement apenas uma vez, ou seja, antes do seu while, com certeza é isso, e se não me engano depois de usado deve ser chamado o método close() nele, depois do while.

Veja se isto já ajuda.

Flw

M

O Problema éra o PreparedStatement que não estava sendo fechado mesmo…

valeu…

josenaldo

Bem, ao que parece você resolveu o problema, mas só para resumir as dicas da galera, pois já passei por um problema semelhante:

  • Lendo arquivos grandes demais? Use a Java NIO

  • Use PreparedStatement ao invés de Statment se for fazer várias inclusões parecidas

  • Se for alterar muito a mesma String, use StringBuilder

  • Lembre-se de desalocar os recursos

Já tive esse problema uma vez. Processando uma série de XMLs com IO normal, levava cerca se 2 horas sem o sistema sequer responder. Só com a mudança para NIO, o sistema passou a responder em absurdos 3 minutos!!!

Java NIO, pra quem nunca usou, deve se parecer com magia negra ou história de pescador… rs

andreengesoft

A classe FileInputStream tb não é má ideia, da uma olhada la na API, ao ir lendo o arquivo e só converter de byte pra string e morreu.

ela classe é bem fácil de trabalhar também com esqueci o nome correto mas tipo separadores como / ( , etc…

valeu :slight_smile:

Grinvon

Se o banco for Oracle.

Eu inventei uma solução mais rápida e prática do que o SQL Loader, e funcionou muito bem.

antoniopopete

Eu usei java.nio e gostei…Na edição do mês passado da mundo java,tem um artigo que fala a respeito.
Não sei se é o seu caso,mas…vale a pena dar uma conferida na API que até onde usei parece que atende.
Exemplo para transferir o conteudo de um arquivo para outro…

FileInputStream fin = new FileInputStream("teste.txt");

FileOutputStream fout = new FileOutputStream("saida.txt");

FineChannel in = fin.getChannel();
FileChannel out = fout.getChanne();

in.transferTo(0,in.size,out);

E antes voce precisaria executar um loop para transferir linha a linha do arquvio.
O uso de String para fazer operações desse tipo,usa muito recurso de memoria use StringBuilder se não precisar de sincronizacao e StringBuffer se precisar…
Mas…eu com meu pequeno conhecimento,acho que seu problema de memoria tem a ver com o uso das Strings…porque voce aaba usando muito recurso de memoria,pq o processo de criacao de objetos imutaveis,como string é muit custoso para JVM.
tente mudar apenas a parte da string para voce usar stringbuilder se tiver no java 1.5 http://java.sun.com/j2se/1.5.0/docs/api/java/lang/StringBuilder.html e stringbuffer se tiver na 1.4 (http://java.sun.com/j2se/1.4.2/docs/api/java/lang/StringBuffer.html

dudaskank

Bem, apesar do que vocês disseram sobre string eu concordar, o nosso colega mark_domi não monta a sql via string, ele usa prepared statement, só estava no local errado sua criação e não liberava o recurso.

Porém, o que foi falado sobre o java.nio também acho bem válido. Infelizmente ainda não tive a honra de utilizá-lo e não sei dizer se neste caso a diferença seria boa, mas não custaria nada tentar e ver o que dá.

E acho que os itens listados pelo josenaldo devem ser memorizados, são simples e dão uma diferença incrível.

:slight_smile:

Criado 17 de janeiro de 2007
Ultima resposta 19 de jan. de 2007
Respostas 12
Participantes 8