Fazer Download de Arquivo com Java

Olá,
Alguem poderia me ajudar, porque eu estou querendo fazer um programa que o usuário final poderia digitar uma URL para um arquivo tipo: “http://www.site.com.br/java/File.zip”. Lembrando que eu sou meio que iniciante.

Obrigado,
Nathan Paulino Campos

Olá nathanpc. Vou apresentar um método pronto (bem simples) que você pode utilizar para gravar arquivos a partir de uma URL.

	public static File gravaArquivoDeURL(String stringUrl, String pathLocal) {
		try {
		
			//Encapsula a URL num objeto java.net.URL
			URL url = new URL(stringUrl);

			//Queremos o arquivo local com o mesmo nome descrito na URL
			//Lembrando que o URL.getPath() ira retornar a estrutura 
			//completa de diretorios e voce deve tratar esta String
			//caso nao deseje preservar esta estrutura no seu disco local.
			String nomeArquivoLocal = url.getPath();
			
			//Cria streams de leitura (este metodo ja faz a conexao)...
			InputStream is = url.openStream();

			//... e de escrita.
			FileOutputStream fos = new FileOutputStream(pathLocal+nomeArquivoLocal);

			//Le e grava byte a byte. Voce pode (e deve) usar buffers para
			//melhor performance (BufferedReader).
			int umByte = 0;
			while ((umByte = is.read()) != -1){
				fos.write(umByte);
			}

			//Nao se esqueca de sempre fechar as streams apos seu uso!
			is.close();
			fos.close();

			//apos criar o arquivo fisico, retorna referencia para o mesmo
			return new File(pathLocal+nomeArquivoLocal);
			
		} catch (Exception e) {
			//Lembre-se de tratar bem suas excecoes, ou elas tambem lhe tratarão mal!
			//Aqui so vamos mostrar o stack no stderr.
			e.printStackTrace();
		}
		   
		return null;
	}

Espero que tenha ajudado. Isto não é exatamente java avançado, e algumas buscas no Google poderiam ter lhe ajudado bastante, pois vários sites oferecem snippets prontos com várias maneiras de executar tarefas corriqueiras como esta.

Veja a descrição das classes e métodos utilizados neste exemplo na especificação da API do Java, e você irá entender exatamente o que o programa faz. Lembre-se que a melhor maneira de aprender é experimentando!

–mcbrain

1 curtida

Olá mcbrain,
Obrigado pelo código, eu o compilo e dá tudo certo, mas quando eu vou executar o arquivo class, ele me volta esse erro:

Obrigado,
Nathan Paulino Campos

[quote=nathanpc]Olá mcbrain,
Obrigado pelo código, eu o compilo e dá tudo certo, mas quando eu vou executar o arquivo class, ele me volta esse erro:

Obrigado,
Nathan Paulino Campos[/quote]

Ah, Nathan, já deu pra ver que você é novo no Java mesmo! :slight_smile:

Para que um arquivo java compilado possa ser executado, ele precisa de um ponto de entrada, o método “main()”.

Coloque o seguinte método antes ou depois do método estático gravaArquivoDeURL() na classe que você está usando, recompile e execute.

	public static void main(String[] args) {
		gravaArquivoDeURL("http://www.google.com.br/index.html","C:\\");
	}

Este exemplo irá gravar a página de índice do Google na raiz do seu PC. Pra não perder a viagem, dê uma olhada nos tutoriais da Sun sobre o Java. Uma vez que você domine os conceitos básicos, vai ficar muito mais fácil criar seus próprios programas. Abraços!

– mcbrain

Muito Obrigado mcbrain, mas sem querer ser muito pidão você poderia me dizer se da para que o usuário digitase a URL para o arquivo, só para melhorar o programa e já saber para mais tarde se eu precisar.

Mas Muito Muito Obrigado,
Nathan Paulino Campos

A forma mais simples é passar a URL como argumento do programa, e já que vamos fazer isso, também passar o path de destino da gravação.

Seu método main, portanto, deverá aceitar 2 argumentos. Veja que ele tem apenas um parâmetro: um array de Strings chamado args. Isto é fixado pela especificação da linguagem Java. A JVM irá encaspular cada argumento da chamada do programa em uma String do parâmetro args, que podem ser referenciados e manipulados dentro do programa. Para usar vários argumentos na chamada do programa, separe-os por um espaço.

Altere o seu método main para o seguinte:

public static void main(String[] args) {
    gravaArquivoDeURL(args[0], args[1]);
}

Após compilado o programa, chame-o com o comando:

java FileDownload http://www.google.com/index.html c:\

[]s
–mcbrain

Muito obrigado mcbrain, muito obrigado mesmo.

Abraços!!

Desculpe minha ignorancia, estou a horas tentando fazer com o Buffered mas não esta indo de jeito nenhum!
Alguem poderia me dar uma ideia de como seria?
Obrigado.

#Edit
Se não fosse pedir muito, como eu pego o nome do arquivo que esta vindo pelo InputStream? Thanks!

[quote=Neri J?ior]Desculpe minha ignorancia, estou a horas tentando fazer com o Buffered mas não esta indo de jeito nenhum!
Alguem poderia me dar uma ideia de como seria?
Obrigado.

#Edit
Se não fosse pedir muito, como eu pego o nome do arquivo que esta vindo pelo InputStream? Thanks![/quote]

Um dos construtores do BufferedWriter recebe um Writer, e um int com o tamanho do buffer como argumentos. Se você estiver escrevendo em um arquivo, pode usar um FileWriter, que por sua vez pode receber um objeto File como argumento no construtor:

BufferedWriter bw = new BufferedWriter(new FileWriter(new File("/home/meuarquivo.txt")),2048);

Depois é só usar o método write() do BufferedWriter e sucesso.

Edit: gramática.

Muito Obrigado!

Olá a todos, estou precisando de uma ajuda.

Estou utilizando a seguinte classe para fazer o download de um arquivo via FTP:

TesteDownloadArquivoExcel

package testemain;

import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Level;
import java.util.logging.Logger;

public class TesteDownloadArqExcel {

    public static void main(String[] args) {
        if (downloadArquivoExcel()) {
            System.out.println("Download concluído com sucesso");
        } else {
            System.out.println("Download não concluído");
        }
    }

    private static boolean downloadArquivoExcel() {
        InputStream is = null;
        BufferedInputStream buf = null;
        FileOutputStream out = null;
        boolean ok = false;
        try {
            URL url = new URL("ftp://User_Name:password@host_ftp/Nome_do_arquivo.xls");
            url.getHost();
            url.getFile();
            url.getPort();
            url.getUserInfo();
            URLConnection con = url.openConnection();
            buf = new BufferedInputStream(con.getInputStream());
            out = new FileOutputStream("c:\\excelDown.xls");

            int i = 0;
            byte[] bytesIn = new byte[1024];
            while ((i = buf.read(bytesIn)) >= 0) {
                out.write(bytesIn, 0, i);
            }
            ok = true;
        } catch (MalformedURLException ex) {
            Logger.getLogger(TesteDownloadArqExcel.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ioe) {
            Logger.getLogger(TesteDownloadArqExcel.class.getName()).log(Level.SEVERE, null, ioe);
        } finally {
            try {
                if (buf != null) {
                    buf.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(TesteDownloadArqExcel.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        if (ok) {
            return ok;
        }
        return false;
    }
}

Ao executar o metodo “con.getInputStream()” estou recebendo uma Exception: “java.net.SocketException: Connection reset”

Alguém poderia me dizer o que estou fazendo de errado?

Desde já grato pela atenção.

FTP é um protocolo. Para que você baixe o arquivo você precisa fazer a requisição (assim como em HTTP, quando você faz um GET ou um POST).

Não basta tentar baixar diretamente. A Apache tem uma API para trabalhar com FTP, talvez seja melhor procurar sobre ela.

Ainda estou tendo problemas, dei uma olhada na documentação “org.apache.commons.net.ftp.FTPClient”, mas ainda está ocorrendo a SocketException.

Modifiquei o codigo do método da classe.

    private static boolean downloadArquivoExcel() {
        BufferedInputStream buf = null;
        FileOutputStream out = null;
        FTPClient ftpCliente = new FTPClient();

        boolean ok = false;
        try {
            ftpCliente.connect("ftp.nome_servidor.com");

            //Verifica se a conectou
            if (FTPReply.isPositiveCompletion(ftpCliente.getReplyCode())) {

                ftpCliente.login("UserName", "Password");

                ftpCliente.setFileType(FTPClient.STREAM_TRANSFER_MODE);

                //Desativa a verificação de HOST
                ftpCliente.setRemoteVerificationEnabled(false);

                out = new FileOutputStream("c:\\excelDown.xls");

                buf = new BufferedInputStream(ftpCliente.retrieveFileStream("/excelDown.xls"));

                //Verifica se download completou
                if (ftpCliente.completePendingCommand()) {
                    int i = 0;
                    byte[] bytesIn = new byte[1024];
                    while ((i = buf.read(bytesIn)) >= 0) {
                        out.write(bytesIn, 0, i);
                    }
                    ok = true;
                }
            } else {
                ftpCliente.disconnect();
                Logger.getLogger(TesteDownloadArqExcel.class.getName()).log(Level.SEVERE, "Não foi possível conectar no servidor FTP para atualização da base estática.");
            }
        } catch (IOException ioe) {
            Logger.getLogger(TesteDownloadArqExcel.class.getName()).log(Level.SEVERE, null, ioe);
        } finally {
            try {
                if (ftpCliente != null) {
                    ftpCliente.disconnect();
                }
                if (buf != null) {
                    buf.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(TesteDownloadArqExcel.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        if (ok) {
            return ok;
        }
        return false;
    }
}

O método de verifcação de HOST já ativei e desativei e continua o problema.

Alguém poderia me ajudar com esse código?
Por favor…

3 coisas:

  1. Você tem certeza que o servidor está OK? Você consegue resgatar esse arquivo se você abrir a linha de comando e se conectar ao servidor?

  2. Em que linha exatamente está ocorrendo a exceção?

  3. O FTPClient já está em modo passivo por padrão? Se não estiver, deve estar.

[quote=marcobiscaro2112]3 coisas:

  1. Você tem certeza que o servidor está OK? Você consegue resgatar esse arquivo se você abrir a linha de comando e se conectar ao servidor?

  2. Em que linha exatamente está ocorrendo a exceção?

  3. O FTPClient já está em modo passivo por padrão? Se não estiver, deve estar.[/quote]

Resposta:
1 - A linha do código de demonstração verifica se conectou corretamente. Em debug verifiquei se estava conectando corretamente. Tudo OK.

2 - Na linha 22 está ocorrendo SocketException.

3 - Sim está por default.

Usei uma solução um tanto quanto grosseira.

Como meu servidor de aplicativo fica em LINUX, usei o Runtime.getRuntime().exec(“Comando a ser executado”), usando o wget passando a url de conexão com o FTP.

Funcionou mas tive de criar um método para ler o arquivo excel, sendo que tive de temporizar para dar tempo do download ser concluido.

Mas fica o meu problema porque eu acho que isso não é um funcionamento normal.

Isso não é normal mesmo. Coloque aqui o stacktrace completo da exceção e certifique-se que é preciso colocar a barra no início do caminho mesmo (ou se ela pode ser omitida). Além disso, tente realizar outras operações, como listar arquivos (vide documentação: http://commons.apache.org/net/api/org/apache/commons/net/ftp/FTPClient.html) e nos diga o resultado.