Como baixar e salvar um arquivo da Internet usando Java?


425

Há um arquivo online (como http://www.example.com/information.asp) que eu preciso pegar e salvar em um diretório. Eu sei que existem vários métodos para capturar e ler arquivos online (URLs) linha por linha, mas existe uma maneira de baixar e salvar o arquivo usando Java?


Respostas:


560

Experimente o Java NIO :

URL website = new URL("http://www.website.com/information.asp");
ReadableByteChannel rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream("information.html");
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);

O uso transferFrom()é potencialmente muito mais eficiente do que um loop simples que lê do canal de origem e grava nesse canal. Muitos sistemas operacionais podem transferir bytes diretamente do canal de origem para o cache do sistema de arquivos sem realmente copiá-los.

Veja mais aqui .

Nota : O terceiro parâmetro em transferFrom é o número máximo de bytes a serem transferidos. Integer.MAX_VALUEtransferirá no máximo 2 ^ 31 bytes, Long.MAX_VALUEpermitirá no máximo 2 ^ 63 bytes (maior que qualquer arquivo existente).


22
Feche todos os três com o try-with-resource do Java 7: try (InputStream inputStream = website.openStream (); ReadableByteChannel readableByteChannel = Channels.newChannel (inputStream); FileOutputStream fileOutputStream = new FileOutputStream (outputFileName)) {fileOutputStream.getChannel (readableByteChannel, 0, 1 << 24); }
mazatwork

80
Isso só vai fazer o download do primeiro 16MB de um arquivo: stackoverflow.com/questions/8405062/downloading-files-with-java
Ben McCann

31
@kirdie e se eu quiser mais do que 8388608TB?
Cruncher

22
Uma única chamada não é adequada. transferFrom()não está especificado para concluir toda a transferência em uma única chamada. É por isso que retorna uma contagem. Você tem que fazer um loop.
Marquês de Lorne

11
Por que essa resposta foi aceita? URL::openStream()retorna apenas um fluxo regular, o que significa que todo o tráfego ainda está sendo copiado através de matrizes Java byte [] em vez de permanecer em buffers nativos. Somente fos.getChannel()é realmente um canal nativo, portanto, a sobrecarga permanece completa. Isso representa zero ganho ao usar o NIO neste caso. Além de estar quebrado, como EJP e Ben MacCann perceberam corretamente.
Ext3h 29/09/2015

495

Use o apache commons-io , apenas um código de linha:

FileUtils.copyURLToFile(URL, File)

22
Agradável! Apenas o que estou procurando! Eu sabia que as bibliotecas Apache já cobriam isso. BTW, é recomendável usar a versão sobrecarregada com parâmetros de tempo limite!
Hendy Irawan

6
... e ao usar essa versão sobrecarregada, lembre-se de que os tempos limite são especificados em milissegundos, não segundos.
László van den Hoek

5
Observe que o copyURLToFileparâmetro timeout está disponível apenas desde a versão 2.0 da biblioteca Commons IO. Veja docs Java
Stanley

6
e se o cabeçalho de autenticação básica tiver que ser adicionado à solicitação? existe uma solução alternativa?
damian

3
Embora seja "curto", na verdade é muito lento.
Meinkraft

123

Uso mais simples do nio:

URL website = new URL("http://www.website.com/information.asp");
try (InputStream in = website.openStream()) {
    Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING);
}

5
Infelizmente, isso silenciosamente falha (baixa 0 bytes) no caso de um redirecionamento como "302 encontrado".
Alexander K

1
@AlexanderK Mas por que você baixaria esse recurso às cegas?
xuesheng 12/01

5
Apesar de ser uma solução elegante, nos bastidores, essa abordagem pode traí-lo silenciosamente. Files.copy (InputStream, Paths, FileOption) delega o processo de cópia para o Files.copy (InputStream, OutputStream). Este último método não verifica o final do fluxo (-1), mas verifica se não há byte lido (0). Isso significa que, se sua rede tiver uma pequena pausa, poderá ler 0 bytes e finalizar o processo de cópia, mesmo que o fluxo não termine para ser baixado pelo sistema operacional.
Miere

6
@Miere É impossível InputStream.read()retornar zero, a menos que você tenha fornecido um buffer ou contagem de comprimento zero, 'pequena pausa' ou não. Ele será bloqueado até que pelo menos um byte seja transferido ou no final do fluxo ou ocorra um erro. Sua reivindicação sobre os internos de Files.copy()é infundada.
Marquês de Lorne

3
Eu tenho um teste de unidade que lê um arquivo binário com 2.6TiB. Usando Files.copy, ele sempre falha no meu servidor de armazenamento HDD (XFS), mas falha apenas algumas vezes no meu SSH. Olhando para o JDK 8, o código do File.copy identifiquei que ele verifica '> 0' para deixar o loop 'while'. Eu apenas copiei exatamente o mesmo código com o -1 e os dois testes de unidade nunca pararam novamente. Depois que o InputStream pode representar descritores de arquivos locais e de rede, e as duas operações de E / S estão sujeitas à alternância de contexto do SO, não consigo entender por que minha reivindicação não tem fundamento. Pode-se afirmar que está funcionando por sorte, mas não causou mais dores de cabeça.
Miere 6/07/16

85
public void saveUrl(final String filename, final String urlString)
        throws MalformedURLException, IOException {
    BufferedInputStream in = null;
    FileOutputStream fout = null;
    try {
        in = new BufferedInputStream(new URL(urlString).openStream());
        fout = new FileOutputStream(filename);

        final byte data[] = new byte[1024];
        int count;
        while ((count = in.read(data, 0, 1024)) != -1) {
            fout.write(data, 0, count);
        }
    } finally {
        if (in != null) {
            in.close();
        }
        if (fout != null) {
            fout.close();
        }
    }
}

Você precisará lidar com exceções, provavelmente externas a esse método.


6
Como baixar muito mais rápido? Como o acelerador de downloads?
precisa saber é

11
Se in.closelança uma exceção, fout.closenão é chamado.
Berílio

1
@ComFreek Isso é simplesmente falso. O uso de a BufferedInputStreamtem um efeito exatamente zero nos tempos limite do soquete. Eu já havia refutado isso como "mito urbano" em meus comentários aos "detalhes de fundo" que você citou. Três anos antes.
Marquês de Lorne

@EJP Obrigado pela correção! Eu removi meu comentário (para o arquivo: vinculei a esta resposta afirmando que BufferedInputStream"pode ​​causar falhas imprevisíveis").
ComFreek 24/07

+1 Minha única objeção a essa resposta (e outras aqui) é que o chamador não pode distinguir o evento "não encontrado" de algum erro de conexão (com o qual você pode tentar novamente).
Leonbloy 20/05

24

É uma pergunta antiga, mas aqui está uma solução concisa, legível e somente para JDK com recursos adequadamente fechados:

public static void download(String url, String fileName) throws Exception {
    try (InputStream in = URI.create(url).toURL().openStream()) {
        Files.copy(in, Paths.get(fileName));
    }
}

Duas linhas de código e sem dependências.


Para quem está se perguntando, eis a importação necessária para este trecho de código:import java.io.InputStream; import java.net.URI; import java.nio.file.Files; import java.nio.file.Paths;
BelovedFool

23

O download de um arquivo requer que você o leia, de qualquer forma, você precisará percorrer o arquivo de alguma maneira. Em vez de linha por linha, você pode simplesmente ler por bytes do fluxo:

BufferedInputStream in = new BufferedInputStream(new URL("http://www.website.com/information.asp").openStream())
    byte data[] = new byte[1024];
    int count;
    while((count = in.read(data,0,1024)) != -1)
    {
        out.write(data, 0, count);
    }

17

Ao usar, Java 7+use o seguinte método para baixar um arquivo da Internet e salve-o em algum diretório:

private static Path download(String sourceURL, String targetDirectory) throws IOException
{
    URL url = new URL(sourceURL);
    String fileName = sourceURL.substring(sourceURL.lastIndexOf('/') + 1, sourceURL.length());
    Path targetPath = new File(targetDirectory + File.separator + fileName).toPath();
    Files.copy(url.openStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);

    return targetPath;
}

Documentação aqui .


16

Essa resposta é quase exatamente igual à resposta selecionada, mas com dois aprimoramentos: é um método e fecha o objeto FileOutputStream:

    public static void downloadFileFromURL(String urlString, File destination) {    
        try {
            URL website = new URL(urlString);
            ReadableByteChannel rbc;
            rbc = Channels.newChannel(website.openStream());
            FileOutputStream fos = new FileOutputStream(destination);
            fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
            fos.close();
            rbc.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

2
Uma única chamada não é adequada. transferFrom()não está especificado para concluir toda a transferência em uma única chamada. É por isso que retorna uma contagem. Você tem que fazer um loop.
Marquês de Lorne

10
import java.io.*;
import java.net.*;

public class filedown {
    public static void download(String address, String localFileName) {
        OutputStream out = null;
        URLConnection conn = null;
        InputStream in = null;

        try {
            URL url = new URL(address);
            out = new BufferedOutputStream(new FileOutputStream(localFileName));
            conn = url.openConnection();
            in = conn.getInputStream();
            byte[] buffer = new byte[1024];

            int numRead;
            long numWritten = 0;

            while ((numRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, numRead);
                numWritten += numRead;
            }

            System.out.println(localFileName + "\t" + numWritten);
        } 
        catch (Exception exception) { 
            exception.printStackTrace();
        } 
        finally {
            try {
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.close();
                }
            } 
            catch (IOException ioe) {
            }
        }
    }

    public static void download(String address) {
        int lastSlashIndex = address.lastIndexOf('/');
        if (lastSlashIndex >= 0 &&
        lastSlashIndex < address.length() - 1) {
            download(address, (new URL(address)).getFile());
        } 
        else {
            System.err.println("Could not figure out local file name for "+address);
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < args.length; i++) {
            download(args[i]);
        }
    }
}

5
Se in.closelança uma exceção, out.closenão é chamado.
Berílio


6

Esta é outra variante java7 baseada na resposta de Brian Risk com o uso da instrução try-with:

public static void downloadFileFromURL(String urlString, File destination) throws Throwable {

      URL website = new URL(urlString);
      try(
              ReadableByteChannel rbc = Channels.newChannel(website.openStream());
              FileOutputStream fos = new FileOutputStream(destination);  
              ){
          fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
      }

  }

Uma única chamada não é adequada. transferFrom()não está especificado para concluir toda a transferência em uma única chamada. É por isso que retorna uma contagem. Você tem que fazer um loop.
Marquês de Lorne

Não sei por que você está me dirigindo essa pergunta estúpida. Não tem nada a ver com o que eu disse, e realmente me recuso a ter palavras na minha boca.
Marquês de Lorne

2

É possível baixar o arquivo com o Apache em HttpComponentsvez de Commons-IO. Esse código permite que você baixe um arquivo em Java de acordo com sua URL e salve-o no destino específico.

public static boolean saveFile(URL fileURL, String fileSavePath) {

    boolean isSucceed = true;

    CloseableHttpClient httpClient = HttpClients.createDefault();

    HttpGet httpGet = new HttpGet(fileURL.toString());
    httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");
    httpGet.addHeader("Referer", "https://www.google.com");

    try {
        CloseableHttpResponse httpResponse = httpClient.execute(httpGet);
        HttpEntity fileEntity = httpResponse.getEntity();

        if (fileEntity != null) {
            FileUtils.copyInputStreamToFile(fileEntity.getContent(), new File(fileSavePath));
        }

    } catch (IOException e) {
        isSucceed = false;
    }

    httpGet.releaseConnection();

    return isSucceed;
}

Em contraste com a única linha de código:

FileUtils.copyURLToFile(fileURL, new File(fileSavePath),
                        URLS_FETCH_TIMEOUT, URLS_FETCH_TIMEOUT);

este código vai lhe dar mais controle sobre um processo e permitem especificar não apenas os pedidos de tempo, mas User-Agente Referervalores, que são críticos para muitos web-sites.


2

Há muitas respostas elegantes e eficientes aqui. Mas a concisão pode nos fazer perder algumas informações úteis. Em particular, geralmente não se deseja considerar um erro de conexão uma exceção e pode-se tratar de forma diferente algum tipo de erro relacionado à rede - por exemplo, para decidir se devemos tentar novamente o download.

Aqui está um método que não lança exceções para erros de rede (apenas para problemas realmente excepcionais, como url malformado ou problemas para gravar no arquivo)

/**
 * Downloads from a (http/https) URL and saves to a file. 
 * Does not consider a connection error an Exception. Instead it returns:
 *  
 *    0=ok  
 *    1=connection interrupted, timeout (but something was read)
 *    2=not found (FileNotFoundException) (404) 
 *    3=server error (500...) 
 *    4=could not connect: connection timeout (no internet?) java.net.SocketTimeoutException
 *    5=could not connect: (server down?) java.net.ConnectException
 *    6=could not resolve host (bad host, or no internet - no dns)
 * 
 * @param file File to write. Parent directory will be created if necessary
 * @param url  http/https url to connect
 * @param secsConnectTimeout Seconds to wait for connection establishment
 * @param secsReadTimeout Read timeout in seconds - trasmission will abort if it freezes more than this 
 * @return See above
 * @throws IOException Only if URL is malformed or if could not create the file
 */
public static int saveUrl(final Path file, final URL url, 
  int secsConnectTimeout, int secsReadTimeout) throws IOException {
    Files.createDirectories(file.getParent()); // make sure parent dir exists , this can throw exception
    URLConnection conn = url.openConnection(); // can throw exception if bad url
    if( secsConnectTimeout > 0 ) conn.setConnectTimeout(secsConnectTimeout * 1000);
    if( secsReadTimeout > 0 ) conn.setReadTimeout(secsReadTimeout * 1000);
    int ret = 0;
    boolean somethingRead = false;
    try (InputStream is = conn.getInputStream()) {
        try (BufferedInputStream in = new BufferedInputStream(is); OutputStream fout = Files
                .newOutputStream(file)) {
            final byte data[] = new byte[8192];
            int count;
            while((count = in.read(data)) > 0) {
                somethingRead = true;
                fout.write(data, 0, count);
            }
        }
    } catch(java.io.IOException e) { 
        int httpcode = 999;
        try {
            httpcode = ((HttpURLConnection) conn).getResponseCode();
        } catch(Exception ee) {}
        if( somethingRead && e instanceof java.net.SocketTimeoutException ) ret = 1;
        else if( e instanceof FileNotFoundException && httpcode >= 400 && httpcode < 500 ) ret = 2; 
        else if( httpcode >= 400 && httpcode < 600 ) ret = 3; 
        else if( e instanceof java.net.SocketTimeoutException ) ret = 4; 
        else if( e instanceof java.net.ConnectException ) ret = 5; 
        else if( e instanceof java.net.UnknownHostException ) ret = 6;  
        else throw e;
    }
    return ret;
}

2

Abaixo está o código de exemplo para baixar filme da internet com código java:

URL url = new 
URL("http://103.66.178.220/ftp/HDD2/Hindi%20Movies/2018/Hichki%202018.mkv");
    BufferedInputStream bufferedInputStream = new  BufferedInputStream(url.openStream());
    FileOutputStream stream = new FileOutputStream("/home/sachin/Desktop/test.mkv");


    int count=0;
    byte[] b1 = new byte[100];

    while((count = bufferedInputStream.read(b1)) != -1) {
        System.out.println("b1:"+b1+">>"+count+ ">> KB downloaded:"+new File("/home/sachin/Desktop/test.mkv").length()/1024);
        stream.write(b1, 0, count);
    }

Geralmente, as respostas são muito mais úteis se incluem uma explicação sobre o que o código pretende fazer e por que isso resolve o problema sem a introdução de outros.
Tim Diekmann 27/05

1

Há um problema com o uso simples de:

org.apache.commons.io.FileUtils.copyURLToFile(URL, File) 

se você precisar baixar e salvar arquivos muito grandes ou, em geral, se precisar de tentativas automáticas, caso a conexão seja interrompida.

O que eu sugiro nesses casos é o Apache HttpClient junto com org.apache.commons.io.FileUtils. Por exemplo:

GetMethod method = new GetMethod(resource_url);
try {
    int statusCode = client.executeMethod(method);
    if (statusCode != HttpStatus.SC_OK) {
        logger.error("Get method failed: " + method.getStatusLine());
    }       
    org.apache.commons.io.FileUtils.copyInputStreamToFile(
        method.getResponseBodyAsStream(), new File(resource_file));
    } catch (HttpException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
    method.releaseConnection();
}

1

Para resumir (e de alguma forma polir e atualizar) as respostas anteriores. Os três métodos a seguir são praticamente equivalentes. (Adicionei tempos limite explícitos porque acho que eles são obrigatórios, ninguém quer que um download seja congelado para sempre quando a conexão for perdida.)

public static void saveUrl1(final Path file, final URL url,
   int secsConnectTimeout, int secsReadTimeout)) 
    throws MalformedURLException, IOException {
    // Files.createDirectories(file.getParent()); // optional, make sure parent dir exists
    try (BufferedInputStream in = new BufferedInputStream(
       streamFromUrl(url, secsConnectTimeout,secsReadTimeout)  );
        OutputStream fout = Files.newOutputStream(file)) {
        final byte data[] = new byte[8192];
        int count;
        while((count = in.read(data)) > 0)
            fout.write(data, 0, count);
    }
}

public static void saveUrl2(final Path file, final URL url,
   int secsConnectTimeout, int secsReadTimeout))  
    throws MalformedURLException, IOException {
    // Files.createDirectories(file.getParent()); // optional, make sure parent dir exists
    try (ReadableByteChannel rbc = Channels.newChannel(
      streamFromUrl(url, secsConnectTimeout,secsReadTimeout) 
        );
        FileChannel channel = FileChannel.open(file,
             StandardOpenOption.CREATE, 
             StandardOpenOption.TRUNCATE_EXISTING,
             StandardOpenOption.WRITE) 
        ) {
        channel.transferFrom(rbc, 0, Long.MAX_VALUE);
    }
}

public static void saveUrl3(final Path file, final URL url, 
   int secsConnectTimeout, int secsReadTimeout))  
    throws MalformedURLException, IOException {
    // Files.createDirectories(file.getParent()); // optional, make sure parent dir exists
    try (InputStream in = streamFromUrl(url, secsConnectTimeout,secsReadTimeout) ) {
        Files.copy(in, file, StandardCopyOption.REPLACE_EXISTING);
    }
}

public static InputStream streamFromUrl(URL url,int secsConnectTimeout,int secsReadTimeout) throws IOException {
    URLConnection conn = url.openConnection();
    if(secsConnectTimeout>0) conn.setConnectTimeout(secsConnectTimeout*1000);
    if(secsReadTimeout>0) conn.setReadTimeout(secsReadTimeout*1000);
    return conn.getInputStream();
}

Não encontro diferenças significativas, tudo parece correto para mim. Eles são seguros e eficientes. (As diferenças de velocidade parecem pouco relevantes - eu escrevo 180 Mb do servidor local em um disco SSD em momentos que variam em torno de 1,2 a 1,5 segs). Eles não exigem bibliotecas externas. Todos trabalham com tamanhos arbitrários e (para minha experiência) redirecionamentos HTTP.

Além disso, todos são lançados FileNotFoundExceptionse o recurso não for encontrado (erro 404, normalmente) e java.net.UnknownHostExceptionse a resolução do DNS falhar; outra IOException corresponde a erros durante a transmissão.

(Marcado como wiki da comunidade, adicione informações ou correções)


1

Existe o método U.fetch (url) na biblioteca underscore-java .

pom.xml:

  <groupId>com.github.javadev</groupId>
  <artifactId>underscore</artifactId>
  <version>1.45</version>

Exemplo de código:

import com.github.underscore.lodash.U;

public class Download {
    public static void main(String ... args) {
        String text = U.fetch("https://stackoverflow.com/questions"
        + "/921262/how-to-download-and-save-a-file-from-internet-using-java").text();
    }
}

Qual é a utilidade dessa resposta quando o link se torna inválido? Por favor, veja Como responder
JimHawkins

Seu código não será compilado. Pergunta pedir solução Java, mas a sua resposta olhar comoJavaScript
TAlex

@talex Adicionei a seção pom.xml e aprimorei o exemplo de código.
Valentyn Kolesnikov

0
public class DownloadManager {

    static String urls = "[WEBSITE NAME]";

    public static void main(String[] args) throws IOException{
        URL url = verify(urls);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        InputStream in = null;
        String filename = url.getFile();
        filename = filename.substring(filename.lastIndexOf('/') + 1);
        FileOutputStream out = new FileOutputStream("C:\\Java2_programiranje/Network/DownloadTest1/Project/Output" + File.separator + filename);
        in = connection.getInputStream();
        int read = -1;
        byte[] buffer = new byte[4096];
        while((read = in.read(buffer)) != -1){
            out.write(buffer, 0, read);
            System.out.println("[SYSTEM/INFO]: Downloading file...");
        }
        in.close();
        out.close();
        System.out.println("[SYSTEM/INFO]: File Downloaded!");
    }
    private static URL verify(String url){
        if(!url.toLowerCase().startsWith("http://")) {
            return null;
        }
        URL verifyUrl = null;

        try{
            verifyUrl = new URL(url);
        }catch(Exception e){
            e.printStackTrace();
        }
        return verifyUrl;
    }
}

Você pode melhorar sua resposta fornecendo informações sobre como seu código funciona, em vez de apenas descartá-lo.
Matej Kormuth 01/07/19

0

Você pode fazer isso em 1 linha usando o netloader para Java :

new NetFile(new File("my/zips/1.zip"), "https://example.com/example.zip", -1).load(); //returns true if succeed, otherwise false.

0

Se você estiver atrás de um proxy, poderá definir os proxies no programa java como abaixo:

        Properties systemSettings = System.getProperties();
        systemSettings.put("proxySet", "true");
        systemSettings.put("https.proxyHost", "https proxy of your org");
        systemSettings.put("https.proxyPort", "8080");

Se você não estiver atrás de um proxy, não inclua as linhas acima no seu código. Código de trabalho completo para baixar um arquivo quando você está atrás de um proxy.

public static void main(String[] args) throws IOException {
        String url="https://raw.githubusercontent.com/bpjoshi/fxservice/master/src/test/java/com/bpjoshi/fxservice/api/TradeControllerTest.java";
        OutputStream outStream=null;
        URLConnection connection=null;
        InputStream is=null;
        File targetFile=null;
        URL server=null;
        //Setting up proxies
        Properties systemSettings = System.getProperties();
            systemSettings.put("proxySet", "true");
            systemSettings.put("https.proxyHost", "https proxy of my organisation");
            systemSettings.put("https.proxyPort", "8080");
            //The same way we could also set proxy for http
            System.setProperty("java.net.useSystemProxies", "true");
            //code to fetch file
        try {
            server=new URL(url);
            connection = server.openConnection();
            is = connection.getInputStream();
            byte[] buffer = new byte[is.available()];
            is.read(buffer);

                targetFile = new File("src/main/resources/targetFile.java");
                outStream = new FileOutputStream(targetFile);
                outStream.write(buffer);
        } catch (MalformedURLException e) {
            System.out.println("THE URL IS NOT CORRECT ");
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("Io exception");
            e.printStackTrace();
        }
        finally{
            if(outStream!=null) outStream.close();
        }
    }

0

1º método usando o novo canal

ReadableByteChannel aq = Channels.newChannel(new url("https//asd/abc.txt").openStream());
FileOutputStream fileOS = new FileOutputStream("C:Users/local/abc.txt")
FileChannel writech = fileOS.getChannel();

Segundo método usando FileUtils

FileUtils.copyURLToFile(new url("https//asd/abc.txt",new local file on system("C":/Users/system/abc.txt"));

Terceiro método usando

InputStream xy = new ("https//asd/abc.txt").openStream();

É assim que podemos baixar o arquivo usando o código java básico e outras bibliotecas de terceiros. Estes são apenas para referência rápida. Pesquise no Google com as palavras-chave acima para obter informações detalhadas e outras opções.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.