web-dev-qa-db-fra.com

Comment télécharger et enregistrer un fichier à partir d'Internet en utilisant Java?

Il existe un fichier en ligne (tel que http://www.example.com/information.asp) que je dois récupérer et enregistrer dans un répertoire. Je sais qu'il existe plusieurs méthodes pour récupérer et lire des fichiers en ligne (URL) ligne par ligne, mais existe-t-il un moyen de simplement télécharger et enregistrer le fichier en utilisant Java?

412
echoblaze

Donnez NIO Java à essayer:

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);

Utiliser transferFrom() est potentiellement bien plus efficace qu'une simple boucle qui lit le canal source et écrit sur ce canal. De nombreux systèmes d'exploitation peuvent transférer des octets directement du canal source dans le cache du système de fichiers sans les copier.

Vérifiez plus à ce sujet ici .

Remarque : le troisième paramètre de transferFrom est le nombre maximal d'octets à transférer. Integer.MAX_VALUE transférera au plus 2 ^ 31 octets, Long.MAX_VALUE autorisera au plus 2 ^ 63 octets (plus volumineux que tout fichier existant).

546
dfa

Utilisez Apache commons-io , un seul code de ligne:

FileUtils.copyURLToFile(URL, File)
477

Utilisation simplifiée des nio:

URL website = new URL("http://www.website.com/information.asp");
try (InputStream in = website.openStream()) {
    Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING);
}
118
xuesheng
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();
        }
    }
}

Vous devrez gérer des exceptions, probablement externes à cette méthode.

85
Ben Noland

Pour télécharger un fichier, vous devez le lire. De toute façon, vous devrez le parcourir en quelque sorte. Au lieu de ligne par ligne, vous pouvez simplement le lire octets à partir du flux:

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);
    }
23
z -

C'est une vieille question mais voici une solution concise, lisible, exclusivement JDK avec des ressources correctement fermées:

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

Deux lignes de code et aucune dépendance.

19
Jan Nielsen

Lorsque vous utilisez Java 7+, appliquez la méthode suivante pour télécharger un fichier d’Internet et enregistrez-le dans un répertoire:

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;
}

Documentation ici .

17
BullyWiiPlaza

Cette réponse est presque identique à la réponse sélectionnée mais avec deux améliorations: il s'agit d'une méthode qui ferme l'objet 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();
        }
    }
15
Brian Risk
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]);
        }
    }
}
10
mumair

Personnellement, j’ai trouvé que HttpClient d’Apache était plus que capable de tout ce que je devais faire à cet égard. Here est un excellent tutoriel sur l'utilisation de HttpClient

8
belgariontheking

Voici une autre variante de Java7 basée sur réponse de Brian Risk avec l'utilisation de l'instruction 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);
      }

  }
6
msangel

Il y a beaucoup de réponses élégantes et efficaces ici. Mais la concision peut nous faire perdre des informations utiles. En particulier, un souvent ne veut pas considérer une erreur de connexion comme une exception, et on peut vouloir traiter différemment un type d'erreur liée au réseau - par exemple, pour décider si nous devons réessayer le téléchargement.

Voici une méthode qui ne génère pas d'exceptions pour les erreurs de réseau (uniquement pour des problèmes vraiment exceptionnels, tels qu'une URL mal formée ou des problèmes d'écriture dans le fichier)

/**
 * 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
leonbloy

Il y a un problème avec l'utilisation simple de:

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

si vous devez télécharger et enregistrer des fichiers très volumineux, ou en général si vous avez besoin de nouvelles tentatives automatiques en cas de perte de la connexion.

Ce que je suggère dans de tels cas, c'est Apache HttpClient avec org.Apache.commons.io.FileUtils. Par exemple:

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
oktieh

Il existe une méthode U.fetch (url) dans la bibliothèque nderscore-Java .

pom.xml:

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

Exemple de code:

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();
    }
}
1

Pour résumer (et en quelque sorte perfectionner et mettre à jour) les réponses précédentes. Les trois méthodes suivantes sont pratiquement équivalentes. (J'ai ajouté des délais d'attente explicites parce que je pense qu'ils sont indispensables. Personne ne veut qu'un téléchargement soit bloqué à jamais lorsque la connexion est perdue.)

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();
}

Je ne trouve pas de différences significatives, tout me semble correct. Ils sont sûrs et efficaces. (Les différences de vitesse semblent peu pertinentes - j’écris 180 Mo de serveur local sur un disque SSD à des moments qui fluctuent entre 1,2 et 1,5 segments). Ils ne nécessitent pas de bibliothèques externes. Tous fonctionnent avec des tailles arbitraires et (selon mon expérience) des redirections HTTP.

De plus, tous jettent FileNotFoundException si la ressource n'est pas trouvée (erreur 404, généralement) et Java.net.UnknownHostException si la résolution DNS a échoué; les autres exceptions IO correspondent à des erreurs lors de la transmission.

(Marqué comme wiki de la communauté, n'hésitez pas à ajouter des informations ou des corrections)

1
leonbloy

Il est possible de télécharger le fichier avec HttpComponents d'Apache au lieu de Commons-IO. Ce code vous permet de télécharger un fichier dans Java en fonction de son URL et de l'enregistrer à la destination spécifique.

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;
}

Contrairement à la seule ligne de code:

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

ce code vous donnera plus de contrôle sur un processus et vous permettra de spécifier non seulement les délais, mais également les valeurs User-Agent et Referer, essentielles pour de nombreux sites Web.

1
Mike B.
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;
    }
}
0
Gegi4321

Vous trouverez ci-dessous un exemple de code permettant de télécharger un film sur Internet avec le code 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);
    }
0
Sachin Rane

Vous pouvez le faire en 1 ligne en utilisant netloader for Java :

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

Si vous êtes derrière un proxy, vous pouvez définir les proxies dans le programme Java comme ci-dessous:

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

Si vous n'êtes pas derrière un proxy, n'incluez pas les lignes ci-dessus dans votre code. Code de travail complet pour télécharger un fichier lorsque vous êtes derrière un 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
bpjoshi