Java.nio

15 respostas
S
Eu estou fazendo uma função que faz o download de um arquivo na internet porém deparei com o seguinte problema:
InputStream stream = url.openStream();
ReadableByteChannel inChannel = Channels.newChannel(stream);
FileChannel outChannel = new FileOutputStream(fileName).getChannel();

//Nesta função o ultimo parâmetro diz quantos bytes serão copiados, como eu vou saber quantos são se a variavel inChannel não fiz nada sobre o tamanho?
outChannel.transferFrom(inChannel, 0, 0);

Obrigado.

15 Respostas

T

Ohoh - que eu saiba, se você vai transferir um arquivo via HTTP, pode solicitar um cabeçalho “Content-Length” para saber o tamanho exato.
Se o servidor não fornecer esse tamanho, você vai ter de usar o velho e bom esquema de ler um pouco de cada vez (sem NIO).

S

Ih, tu ta certo. Valeu. A propósito, qual o comando para solicitar o content-length? Ou talvez não seria melhor usar o java.io direto, pois não estou usando o java.nio por alguma razão especial…

T

Em vez de

InputStream stream = url.openStream();

use

URLConnection conn = url.openConnection();
InputStream stream = conn.getOutputStream();
... = conn.getContentLength();

para obter esse header.

S

Estranho, sempre me retorna -1. Mesmo conectando no google por exemplo.

URLConnection connection = url.openConnection();
        ReadableByteChannel inChannel = Channels.newChannel(connection.getInputStream());
        FileChannel outChannel = new FileOutputStream(fileName).getChannel();

        outChannel.transferFrom(inChannel, 0, connection.getContentLength());
T

Talvez Content-Length só seja setado corretamente quando você vai baixar uma figura estática, por exemplo. Se for baixar uma página gerada dinamicamente pode ser que o servidor não mande esse valor.

S

Ah, ok então vamo pelo velho java.io mesmo então. Eu posso copiar os bytes da URl direto pros bytes do arquivo sem convertelos pra char né?

S

Enfim, eu fiz com o java.io copiando de 1024 em 1024 bytes da url pro arquivo só que no inicio da primeira linha ficou certo só que depois ficou em branco. Alguma idéia?

InputStream input = null;
        FileOutputStream output = null;
        
        try {
            input = url.openStream();
            output = new FileOutputStream(fileName);
        
            byte [] bytes = new byte[1024];
        
            while (input.read(bytes) != -1) {
                output.write(bytes);
            }
        } finally {
            input.close();
            output.close();
        }

1ª linha ficou - <meta http-equi
Mas deveria ser - Google<!–

URL Testada = www.google.com

T

Em vez disto:

while (input.read(bytes) != -1) {
                 output.write(bytes);
             }

Use isto:

int nBytes;
while ((nBytes = input.read(bytes)) &gt 0) {
    output.write (bytes, 0, nBytes);
}
S

Ah, claro. Mas porque tenho que fazer isso? O length não fica armazenado em bytes.length?

T

Não, porque uma rotina Java não pode redimensionar um array passado como parâmetro. Lembre-se:

  • o tamanho de um array não pode ser alterado depois de sua criação.
  • em Java as referências dos objetos são passados por valor.

Se read tivesse a seguinte assinatura:

byte[] read()

ou seja,

bytes = input.read();

então read poderia voltar um array com o tamanho exato a ser transferido. Mas não é assim que funciona.

S

Pior, acostumado com os tempos de C++ hehehe. Não tem algum jeito de passar um parâmetro por referência?

T

“As referências aos objetos são passadas por valor” (isso dá um nó na cabeça no começo, piora um pouco depois, e depois você ou entende ou então só repete como um mantra).

Se o objeto for mutável, não há problemas em mudar seu estado, mas um método não pode mudar um parâmetro “de” objeto - só pode mudar “o” objeto, e ainda assim se ele deixar. (Por exemplo, você não pode mudar o valor de um java.lang.Integer).

Object obj = ...;
q.meuMetodo (obj);
System.out.println (obj); // em Java você tem certeza absoluta que
// obj continua a se referir ao mesmo objeto, mesmo que tenha
// sido internamente mudado.

Em C#:

object obj = ...;
q.meuMetodo (ref obj); // "ref" avisa ao programador
// que "meuMetodo" tem o direito de mudar o objeto para o qual "obj" aponta
Console.WriteLine (obj); // será que obj é o mesmo, ou foi mudado?
S

Obrigado, ja entendi.

E para acesar um arquivo de caracteres vocês consideram as classes do pacote java.io ou as do java.nio mais rapidas?

T

Para um arquivo texto acho mais fácil usar BufferedReader para ler linha-a-linha, e BufferedWriter para escrever linha-a-linha. Só pôr um valor razoável para o buffer (cerca de 8 a 16 KB).

S

Eu posso especificar o tamanho do buffer? Como?

Criado 2 de junho de 2007
Ultima resposta 3 de jun. de 2007
Respostas 15
Participantes 2