Как скачать и сохранить файл из Интернета с помощью Java?

Есть онлайн файл (например,http://www.example.com/information.asp) Мне нужно захватить и сохранить в каталог. Я знаю, что есть несколько способов построчного захвата и чтения онлайн-файлов (URL), но есть ли способ просто загрузить и сохранить файл с помощью Java?

 Adrien Be11 июл. 2013 г., 09:00

Ответы на вопрос(20)

Упрощенное использование nio:

URL website = new URL("http://www.website.com/information.asp");
try (InputStream in = website.openStream()) {
    Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING);
}
 user20742105 июл. 2016 г., 11:26
@Miere невозможно дляInputStream.read() возвращать ноль, если вы не предоставили буфер нулевой длины или счетчик, «небольшую паузу» или иное. Он будет блокироваться до тех пор, пока не будет передан хотя бы один байт или пока не закончится поток или не произойдет ошибка. Ваша претензия о внутренних органахFiles.copy() безосновательно
 Miere06 июл. 2016 г., 18:50
У меня есть модульный тест, который читает двоичный файл с 2,6 ТБ. Использование Files.copy всегда приводит к сбою на моем сервере хранения HDD (XFS), но это происходит только несколько раз по моему SSH. Глядя на JDK 8, код File.copy, который я обнаружил, проверяет, чтобы '> 0' покинул цикл while. Я просто скопировал один и тот же код с -1, и оба модульных теста больше никогда не останавливались. Как только InputStream может представлять дескрипторы сетевых и локальных файлов, и обе операции ввода-вывода подлежат переключению контекста ОС, я не могу понять, почему мое утверждение является необоснованным. Кто-то может утверждать, что это работает удачей, но больше не доставляло головной боли.
 xuesheng12 янв. 2016 г., 19:23
@AlexanderK Но зачем вам вслепую скачивать такой ресурс?
 Miere13 апр. 2016 г., 15:17
Несмотря на то, что это элегантное решение, за кулисами такой подход мог бы молчаливо предать вас. Files.copy (InputStream, Paths, FileOption) делегирует процесс копирования в Files.copy (InputStream, OutputStream). Этот последний метод не проверяет конец потока (-1), но проверяет отсутствие чтения байта (0). Это означает, что если в вашей сети была небольшая пауза, она могла бы прочитать 0 байтов и завершить процесс копирования, даже если поток не завершен для загрузки ОС.
 Alexander K09 янв. 2016 г., 06:43
К сожалению, это происходит молча (загрузка 0 байтов) в случае перенаправления, такого как «302 Найдено».

Вы можете сделать это в 1 строку, используясетевой загрузчик для Java:

new NetFile(new File("my/zips/1.zip"), "https://example.com/example.zip", -1).load(); //returns true if succeed, otherwise false.
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;
    }
}
 Matej Kormuth02 июл. 2017 г., 00:26
Вы можете улучшить свой ответ, предоставив информацию о том, как работает ваш код, а не просто выгрузив его.
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]);
        }
    }
}
 Beryllium09 авг. 2013 г., 17:17
Еслиin.close выдает исключение,out.close не называется.

это метод, и он закрывает объект 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();
        }
    }
 Brian Risk28 мая 2015 г., 16:37
Спасибо, Мануэль! Готово.
 user20742105 июл. 2016 г., 11:30
Один звонок не подходит.transferFrom() isnt 'указан для завершения всей передачи за один вызов. Вот почему он возвращает счет. Вы должны зациклить.
 Manuel27 мая 2015 г., 15:43
Вы должны также закрыть rbc.
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();
        }
    }
}

возможно, внешние для этого метода.

 meain10 апр. 2014 г., 18:54
Как показать процент загруженного
 digz666610 янв. 2012 г., 08:08
Как скачать очень быстро? Нравится ускоритель загрузки?
 user20742123 июл. 2014 г., 04:33
@ComFreek Это просто неправда. С помощьюBufferedInputStream имеет точно нулевой эффект на время ожидания сокета. Я уже опроверг это как «городской миф» в моих комментариях к «второстепенным деталям», которые вы цитировали. Тремя годами ранее
 Beryllium09 авг. 2013 г., 17:15
Еслиin.close выдает исключение,fout.close не называется.
 ComFreek24 июл. 2014 г., 17:53
@EJP Спасибо за исправление! Я удалил свой комментарий (для архива: я связался сэтот ответ основываясь на этомBufferedInputStream «может вызвать непредсказуемые сбои»).

анием кода 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);
    }
 Tim Diekmann27 мая 2018 г., 13:18
Как правило, ответы гораздо полезнее, если они включают в себя объяснение того, для чего предназначен код, и почему это решает проблему, не представляя других.

Apache's HttpClient быть более чем способным ко всему, что мне нужно было сделать в связи с этим.Вот отличный учебник по использованию HttpClient

 dfa28 мая 2009 г., 17:32
Также Commons-IO это отличная библиотека

Использовать apacheОбще-ю, всего одна строка кода:

FileUtils.copyURLToFile(URL, File)
 Hendy Irawan23 янв. 2012 г., 16:11
Приятно! Как раз то, что я ищу! Я знал, что библиотеки Apache уже охватят это. Кстати, рекомендуется использовать перегруженную версию с параметрами тайм-аута!
 Stanley12 апр. 2013 г., 06:00
Обратите внимание, чтоcopyURLToFile Параметр timeout доступен только с версии 2.0 библиотеки ввода-вывода Commons. ВидетьJava документы
 damian02 апр. 2015 г., 16:30
Что, если к запросу нужно добавить заголовок базовой аутентификации? есть ли обходной путь?
 Magno C25 нояб. 2014 г., 12:38
Это должен быть принятый ответ
 László van den Hoek06 июл. 2012 г., 14:00
... и при использовании этой перегруженной версии помните, что время ожидания указывается в миллисекундах, а не секундах.

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

Краткие, удобочитаемые, правильно закрытые ресурсы, не использующие ничего, кроме основных функций JDK и языка.

заставить нас потерять некоторую полезную информацию. В частности, одинчасто не хочет считать ошибку соединения исключениеми можно по-разному относиться к каким-либо сетевым ошибкам, например, чтобы решить, следует ли повторить загрузку.

Вот метод, который не выдает Исключения для сетевых ошибок (только для действительно исключительных проблем, таких как неправильный URL-адрес или проблемы с записью в файл)

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

основанный наОтвет Брайана Риска с использованием оператора 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);
      }

  }
 user20742105 июл. 2016 г., 11:30
Один звонок не подходит.transferFrom() isnt 'указан для завершения всей передачи за один вызов. Вот почему он возвращает счет. Вы должны зациклить.
 user20742130 июл. 2017 г., 17:31
Я не знаю, почему вы задаете мне этот глупый вопрос. Это не имеет ничего общего с тем, что я сказал, и я действительно отказываюсь вставлять слова в мой рот.

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

если вам нужно скачать и сохранить очень большие файлы, или вообще, если вам нужны автоматические повторные попытки в случае разрыва соединения.

В таких случаях я предлагаю Apache HttpClient вместе с org.apache.commons.io.FileUtils. Например:

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

в любом случае вам придется каким-то образом просматривать файл. Вместо того, чтобы построчно, вы можете просто прочитать его байтами из потока:

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);
    }
Решение Вопроса

Дать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);

С помощьюtransferFrom() являетсяпотенциально гораздо эффективнее, чем простой цикл, который читает из исходного канала и пишет в этот канал. Многие операционные системы могут передавать байты непосредственно из исходного канала в кеш файловой системы, фактически не копируя их.

Проверьте больше об этомВот.

Запись: Третий параметр в TransferFrom - это максимальное количество байтов для передачи.Integer.MAX_VALUE будет передавать не более 2 ^ 31 байтов,Long.MAX_VALUE позволит максимально 2 ^ 63 байта (больше, чем любой существующий файл).

 mazatwork08 нояб. 2012 г., 10:44
Закройте все три с помощью Java 7 try-with-resource: try (InputStream inputStream = website.openStream (); ReadableByteChannel readableByteChannel = Channels.newChannel (inputStream); FileOutputStream fileOutputStream = новый FileOutputStream (outputFileName)) {fileOutputFream (). (readableByteChannel, 0, 1 << 24); }
 Cruncher15 окт. 2013 г., 16:02
@ kirdie и если я хочу больше, чем8388608 ТБ?
 Ben McCann12 янв. 2013 г., 22:04
Это загрузит только первые 16 МБ файла:stackoverflow.com/questions/8405062/downloading-files-with-java
 user20742123 июл. 2014 г., 04:32
Один звонок не подходит.transferFrom() isnt 'указан для завершения всей передачи за один вызов. Вот почему он возвращает счет. Вы должны зациклить.
 Ext3h29 сент. 2015 г., 11:54
Почему этот ответ даже был принят?URL::openStream()возвращает обычный поток, то есть весь трафик все еще копируется через массивы Java byte [], а не остается в собственных буферах. Толькоfos.getChannel()на самом деле нативный канал, поэтому накладные расходы остаются в полном объеме. Это нулевая выгода от использования NIO в этом случае. Помимо того, что EJP и Бен Макканн правильно заметили, что они сломаны.

ри следующих метода практически эквивалентны. (Я добавил явные тайм-ауты, потому что я думаю, что они просто необходимы, никто не хочет, чтобы загрузка зависла навсегда, когда соединение потеряно.)

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

Я не нахожу существенных различий, мне все кажется правильным. Они безопасны и эффективны. (Различия в скорости кажутся едва уместными - я записываю 180Mb с локального сервера на SSD-диск в разы, которые колеблются от 1,2 до 1,5 сегментов). Они не требуют внешних библиотек. Все работают с произвольными размерами и (по моему опыту) перенаправления HTTP.

Дополнительно все бросаютFileNotFoundException если ресурс не найден (обычно ошибка 404), иjava.net.UnknownHostException если разрешение DNS не удалось; Другие IOException соответствуют ошибкам при передаче.

(Помечено как вики сообщества, не стесняйтесь добавлять информацию или исправления)

подчеркнуть, ява библиотека.

pom.xml:

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

Пример кода:

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();
    }
}
 talex25 июл. 2017 г., 14:10
Ваш код не будет компилироваться. Вопрос задайте для решения вJavaно твой ответ похожJavaScript
 Valentyn Kolesnikov30 июл. 2017 г., 12:19
@talex Я добавил раздел pom.xml и улучшил пример кода.
 JimHawkins25 июл. 2017 г., 10:10
Насколько полезен этот ответ, когда ссылка становится недействительной? Пожалуйста, посмотрите наКак ответить

Когда используешьJava 7+ используйте следующий метод, чтобы загрузить файл из Интернета и сохранить его в каком-либо каталоге:

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

ДокументацияВот.

вы можете установить прокси в java программе, как показано ниже:

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

Если вы не используете прокси-сервер, не включайте приведенные выше строки в ваш код. Полный рабочий код для загрузки файла, когда вы находитесь за прокси.

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

Можно скачать файл с помощью ApacheHttpComponents вместоCommons-IO, Этот код позволяет загружать файл в Java в соответствии с его URL-адресом и сохранять его в определенном месте назначения.

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

В отличие от одной строки кода:

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

этот код даст вам больше контроля над процессом и позволит вам указать не только время ожидания, но иUser-Agent а такжеReferer ценности, которые имеют решающее значение для многих веб-сайтов.

Ваш ответ на вопрос