Como ler um arquivo grande com inputstream sem estourar memória
16 respostas
kleberaugus
Seguinte, estou tentando ler arquivos com inputstream, preciso lê-los e depois trata-los para depois gravar novamente, o problema é como vou ler estes arquivos, se eu colocar inputstream.read, vai ler byte por byte mas pelo que li isso é lento, então pensei ler vários bytes de uma vez em uma array, porém para arquivos grandes não sei se dá pra fazer uma array tão grande, uma pessoa falou para criar um buffer e me passou esse código:FileInputStream fis = newTexto pré-formatado`FileInputStream(new File(“C:/arquivo.dat”));
Porém não entendi esse código, como eu tenho acesso aos dados para guardá-los em variáveis e poder tratá-los? Não sei como acessar os dados, ver os dados…
Consegui lendo a array buffer mas e se eu quizer arquivos maiores que 2048 bytes? Tipo um arquivo de 1 giga?
lvbarbosa
Você precisa carregar o dado inteiro em memória para tratá-lo? Não pode ler pequenas partes, tratá-las, liberar a memória e em seguida ir para a próxima parte?
kleberaugus
É exatamente isso que vc falou que eu quero fazer, mas não sei como.
lvbarbosa
Pra isso você precisa saber qual é o tamanho de uma unidade de trabalho. Quantos bytes você precisa para ter algo com o qual pode trabalhar? O tamanho das unidades é fixo ou varia?
kleberaugus
Por exemplo, se eu leio 1000 bytes, como eu faço para na próxima vez recomeçar do 1001 e não do zero, e como eu faço isso sabendo o tamanho do arquivo todo?
kleberaugus
Eu quero tratar uns 5 bits por vez, mas pensei que baixar vários bytes de uma vez seria mais rápido.
lvbarbosa1 like
Essa é exatamente a definição de uma Stream. Conforme você vai lendo, a stream vai sendo consumida. Quando você pega uma quantidade de bytes, você os tira da Stream. A próxima leitura vai devolver bytes diferentes dos primeiros. A Stream é sequencial por definição.
Um exemplo, digamos que a stream tem 10 bytes:
abcdefghij
Se você pedir 2 bytes para ela, a resposta vai ser: ab. A stream vai ficar dessa forma:
cdefghij
Se você pedir mais 2 bytes, a nova resposta vai ser: cd. A stream vai ficar assim:
efghij
E assim por diante, até chegar no final e quando você tentar ler ela te falar que leu -1 bytes.
kleberaugus
O problema é que nesse código que postei, se a array de buffer não tiver o número total de bytes do arquivo, ele não lê tudo, só lê o tanto de bytes que pôs, mas aí como eu faço pra ler o resto?
lvbarbosa
Mas você não precisa saber o tamanho inteiro do arquivo, jovem. O exemplo foi só para ilustrar como streams funcionam. Quando você cria uma FileInputStream, a JVM não copia o arquivo inteiro para memória. Ela pega apenas uma parte do arquivo. Conforme você vai consumindo a stream, ela vai carregando mais partes do arquivo na memória e colocando os novos bytes no final da stream. Mas você (seu código) não precisa saber desse detalhe. Trabalhe com a abstração InputStream, que é: uma sequência de bytes. Não interessa de onde esses bytes vem nem como eles estão sendo carregados.
O que você precisa saber é de quantos bytes você precisa para conseguir fazer alguma coisa com o dado.
Se o problema fosse, por exemplo, ler um arquivo cheio de números inteiros de 4 bytes, incrementar todos e salvar em um arquivo novo, seu buffer só precisa de 4 bytes. O algoritmo seria:
Lê 4 bytes da stream (se a stream retornar que não leu nada, acaba o programa);
Transforma isso num int;
Incrementa o número;
Escreve o resultado na stream de saída. Retorna para #1.
Tudo depende do que você está tentando resolver.
lvbarbosa
Um loop, enquanto a stream retorna dados você continua executando o algoritmo.
kleberaugus
Ah tá tinha me esquecido disso, eu tenho a seguinte linha: int readBytes = inputstream.read(buffer, 0, 2048); eu posso colocar no loop while(readbytes!=-1){}, Valeu, muito obrigado pelas respostas!
O problema é que eu tenho que definir o tamanho da array, e se eu coloco um tamanho menor que o tamanho total do arquivo, dá pau no arquivo de saída, ou seja, ele não lê tudo.
lvbarbosa
Ao invés de for(int i = 0;i<2048;i++), coloque for (int i = 0; i < readBytes; i++).
kleberaugus
ahnnnn MUITO OBRIGADO!
kleberaugus
Sem querer ser chato, mas já sendo: o que está ocorrendo agora é que estou lendo o arquivo original e reescrevendo sem nenhum tratamento, só pra ver se o código está certo, logo, o arquivo escrito deve ficar igual ao arquivo original, o problema é que o arquivo escrito está ficando exatamente 2048 bytes de tamanho, menor que o original, estou fazendo while (readBytes!=0)…
kleberaugus
O arquivo final está exatamente 2048 bytes menor que o original!