Eu estou fazendo uma função que faz o download de um arquivo na internet porém deparei com o seguinte problema:
[code]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);[/code]
Obrigado.
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).
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…
Em vez de
InputStream stream = url.openStream();
use
URLConnection conn = url.openConnection();
InputStream stream = conn.getOutputStream();
... = conn.getContentLength();
para obter esse header.
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());
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.
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é?
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
Em vez disto:
while (input.read(bytes) != -1) {
output.write(bytes);
}
Use isto:
int nBytes;
while ((nBytes = input.read(bytes)) > 0) {
output.write (bytes, 0, nBytes);
}
Ah, claro. Mas porque tenho que fazer isso? O length não fica armazenado em bytes.length?
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.
Pior, acostumado com os tempos de C++ hehehe. Não tem algum jeito de passar um parâmetro por referência?
“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?
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?
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).
Eu posso especificar o tamanho do buffer? Como?