使用nio多线程下载网络文件实例

代码:


import io.github.viscent.mtia.util.Debug;
import io.github.viscent.mtia.util.Tools;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;

import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;

public class FileDownloaderApp {

  public static void main(String[] args) {
  String[]pics =new String[]{"https://dlqn.aoscdn.com/beecut-setup-pin.exe",
    "https://scpic.chinaz.net/files/pic/pic9/202112/apic37306.jpg"};
    Thread downloaderThread = null;
    for (String url : pics) {
      // 创建文件下载器线程
      downloaderThread = new Thread(new FileDownloader(url));
      // 启动文件下载器线程
      downloaderThread.start();
    }
  }

  // 文件下载器线程类,拓展runnable接口
  static class FileDownloader implements Runnable {
    private final String fileURL;

    public FileDownloader(String fileURL) {
      this.fileURL = fileURL;
    }
//在run方法中获取文件夹路径,调用下载文件的方法进行下载
    @Override
    public void run() {
      Debug.info("Downloading from " + fileURL);
      String fileBaseName = fileURL.substring(fileURL.lastIndexOf('/') + 1);
      try {
        URL url = new URL(fileURL);
        String localFileName = System.getProperty("java.io.tmpdir")//自己电脑系统的临时文件夹路径位置

            + fileBaseName;
        Debug.info("Saving to: " + localFileName);
        downloadFile(url, new FileOutputStream(
            localFileName), 1024);
      } catch (Exception e) {
        e.printStackTrace();
      }
      Debug.info("Done downloading from " + fileURL);
    }

    // 从指定的URL下载文件,并将其保存到指定的输出流中,在这里使用了nio的 ReadableByteChannel和WritableByteChannel    用方法 buf.flip();
// outChannel.write(buf);从给定的缓冲区将字节序列写入此通道
    private void downloadFile(URL url, OutputStream outputStream, int bufSize)
        throws MalformedURLException, IOException {
      // 建立HTTP连接
      final HttpURLConnection httpConn = (HttpURLConnection) url
          .openConnection();
      httpConn.setRequestMethod("GET");
      ReadableByteChannel inChannel = null;
      WritableByteChannel outChannel = null;
      try {
        // 获取HTTP响应码
        int responseCode = httpConn.getResponseCode();
        // HTTP响应非正常:响应码不为2开头
        if (2 != responseCode / 100) {
          throw new IOException("Error: HTTP " + responseCode);
        }

        if (0 == httpConn.getContentLength()) {
          Debug.info("Nothing to be downloaded " + fileURL);
          return;
        }
        inChannel = Channels
            .newChannel(new BufferedInputStream(httpConn.getInputStream()));
        outChannel = Channels
            .newChannel(new BufferedOutputStream(outputStream));
        ByteBuffer buf = ByteBuffer.allocate(bufSize);
        while (-1 != inChannel.read(buf)) {
          buf.flip();
          outChannel.write(buf);
          buf.clear();
        }
      } finally {
        // 关闭指定的Channel以及HttpURLConnection
        Tools.silentClose(inChannel, outChannel);
        httpConn.disconnect();
      }
    }// downloadFile结束
  }// FileDownloader结束
}

其中Debug为自定义的工具类


import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Debug {
  private static ThreadLocal<SimpleDateFormat> sdfWrapper = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
      return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    }

  };

  enum Label {
    INFO("INFO"),
    ERR("ERROR");
    String name;

    Label(String name) {
      this.name = name;
    }

    public String getName() {
      return name;
    }
  }

  // public static void info(String message) {
  // printf(Label.INFO, "%s", message);
  // }

  public static void info(String format, Object... args) {
    printf(Label.INFO, format, args);
  }

  public static void info(boolean message) {
    info("%s", message);
  }

  public static void info(int message) {
    info("%d", message);
  }

  public static void error(String message, Object... args) {
    printf(Label.ERR, message, args);
  }

  public static void printf(Label label, String format, Object... args) {
    SimpleDateFormat sdf = sdfWrapper.get();
    @SuppressWarnings("resource")
    final PrintStream ps = label == Label.INFO ? System.out : System.err;
    ps.printf('[' + sdf.format(new Date()) + "][" + label.getName()
        + "]["
        + Thread.currentThread().getName() + "]:" + format + " %n", args);
  }
}

其中tools关闭文件的方法:


public final class Tools {
  private static final Random rnd = new Random();
  private static final Logger LOGGER = Logger.getAnonymousLogger();

  public static void startAndWaitTerminated(Thread... threads)
      throws InterruptedException {
    if (null == threads) {
      throw new IllegalArgumentException("threads is null!");
    }
    for (Thread t : threads) {
      t.start();
    }
    for (Thread t : threads) {
      t.join();
    }
  }

  public static void startAndWaitTerminated(Iterable<Thread> threads)
      throws InterruptedException {
    if (null == threads) {
      throw new IllegalArgumentException("threads is null!");
    }
    for (Thread t : threads) {
      t.start();
    }
    for (Thread t : threads) {
      t.join();
    }
  }

  public static void randomPause(int maxPauseTime) {
    int sleepTime = rnd.nextInt(maxPauseTime);
    try {
      Thread.sleep(sleepTime);
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
    }
  }

  public static void randomPause(int maxPauseTime, int minPauseTime) {
    int sleepTime = maxPauseTime == minPauseTime ? minPauseTime : rnd
        .nextInt(maxPauseTime - minPauseTime) + minPauseTime;
    try {
      Thread.sleep(sleepTime);
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
    }
  }

  public static void silentClose(Closeable... closeable) {
    if (null == closeable) {
      return;
    }
    for (Closeable c : closeable) {
      if (null == c) {
        continue;
      }
      try {
        c.close();
      } catch (Exception ignored) {
      }
    }
  }

  public static void split(String str, String[] result, char delimeter) {
    int partsCount = result.length;
    int posOfDelimeter;
    int fromIndex = 0;
    String recordField;
    int i = 0;
    while (i < partsCount) {
      posOfDelimeter = str.indexOf(delimeter, fromIndex);
      if (-1 == posOfDelimeter) {
        recordField = str.substring(fromIndex);
        result[i] = recordField;
        break;
      }
      recordField = str.substring(fromIndex, posOfDelimeter);
      result[i] = recordField;
      i++;
      fromIndex = posOfDelimeter + 1;
    }
  }

  public static void log(String message) {
    LOGGER.log(Level.INFO, message);
  }

  public static String md5sum(final InputStream in) throws NoSuchAlgorithmException, IOException {
    MessageDigest md = MessageDigest.getInstance("MD5");
    byte[] buf = new byte[1024];
    try (DigestInputStream dis = new DigestInputStream(in, md)) {
      while (-1 != dis.read(buf)){}
        ;
    }
    byte[] digest = md.digest();
    BigInteger bigInt = new BigInteger(1, digest);
    String checkSum = bigInt.toString(16);

    while (checkSum.length() < 32) {
      checkSum = "0" + checkSum;
    }
    return checkSum;
  }

  public static String md5sum(final File file) throws NoSuchAlgorithmException, IOException {
    return md5sum(new BufferedInputStream(new FileInputStream(file)));
  }

  public static void delayedAction(String prompt, Runnable action, int delay/* seconds */) {
    Debug.info("%s in %d seconds.", prompt, delay);
    try {
      Thread.sleep(delay * 1000);
    } catch (InterruptedException ignored) {
    }
    action.run();
  }

  public static Object newInstanceOf(String className) throws InstantiationException,
      IllegalAccessException, ClassNotFoundException {
    return Class.forName(className).newInstance();
  }

}

结果:
可以看到这里开了两个线程用于下载上面的两个链接
在这里插入图片描述

文件夹下面可以看到刚刚自己下载好的两个文件:
在这里插入图片描述

打开图片也可以看到完整的图片显示:
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值