【第85题】JAVA高级技术-网络编程4(网络资源的多线程下载)

举报
小虚竹 发表于 2022/06/14 23:31:32 2022/06/14
【摘要】 回城传送–》《JAVA筑基100例》 文章目录 零、前言一、题目描述二、解题思路三、代码详解四、推荐专栏五、示例源码下载 零、前言 ​ 今天是学习 JAVA语言 打卡的第85天,每天我会...

回城传送–》《JAVA筑基100例》

零、前言

​ 今天是学习 JAVA语言 打卡的第85天,每天我会提供一篇文章供群成员阅读( 不需要订阅付钱 ),读完文章之后,按解题思路,自己再实现一遍。在小虚竹JAVA社区 中对应的 【打卡贴】打卡,今天的任务就算完成了。

​ 因为大家都在一起学习同一篇文章,所以有什么问题都可以在群里问,群里的小伙伴可以迅速地帮到你,一个人可以走得很快,一群人可以走得很远,有一起学习交流的战友,是多么幸运的事情。

​ 学完后,自己写篇学习报告的博客,可以发布到小虚竹JAVA社区 ,供学弟学妹们参考。

​ 我的学习策略很简单,题海策略+ 费曼学习法。如果能把这100题都认认真真自己实现一遍,那意味着 JAVA语言 已经筑基成功了。后面的进阶学习,可以继续跟着我,一起走向架构师之路。

一、题目描述

题目实现:主线程启动后,通过单独的线程完成文件的下载。

二、解题思路

创建一个类:DownMultiThread,实现Runnable

在线程的run方法里实现文件的下载

创建一个类:MultiThreadDownFrame,继承JFrame窗体类。

定义一个download()方法:用于调用线程类DownMultiThread下载文件。

在线程类中,下载时指定线程数,通过RandomAccessFile类的seek()方法定位下一个写入点,然后通过write()方法写入文件,实现多线程下载。

测试下载这个链接:http://xz.w10a.com/small/FeiRarInstall.rar

三、代码详解

DownMultiThread

package com.xiaoxuzhu;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.swing.JOptionPane;
/**
 * Description: 
 *
 * @author xiaoxuzhu
 * @version 1.0
 *
 * <pre>
 * 修改记录:
 * 修改后版本	        修改人		修改日期			修改内容
 * 2022/5/24.1	    xiaoxuzhu		2022/5/24		    Create
 * </pre>
 * @date 2022/5/24
 */
public class DownMultiThread implements Runnable{
    private String sUrl = "";// 网络资源地址
    private File desFile;// 需要写入的目标文件对象
    private long startPos;// 写入的开始位置
    private long endPos;// 写入的结束位置
    /**
     * @param sUrl 网络资源地址
     * @param desFile 需要写入的目标文件对象
     * @param startPos 写入的开始位置
     * @param endPos 写入的结束位置
     */
    public DownMultiThread(String sUrl,File desFile,long startPos,long endPos) {
        this.sUrl = sUrl;
        this.desFile = desFile;
        this.startPos = startPos;
        this.endPos = endPos;
    }
    @Override
    public void run() {
        try {
            URL url = new URL(sUrl);// 创建下载资源的URL对象
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();// 打开连接对象
            conn.setRequestProperty("User-Agent", "NetFox");// 设置请求属性
            String rangeProperty = "bytes="+startPos+"-";// 定义范围属性
            if (endPos > 0){
                rangeProperty = "bytes="+startPos+"-" + endPos;// 调整范围属性的值
            }
            conn.setRequestProperty("RANGE", rangeProperty);// 指定范围属性
            RandomAccessFile out = new RandomAccessFile(desFile, "rw");// 创建可读写的流对象
            out.seek(startPos);// 指定读写的开始标记
            InputStream in = conn.getInputStream();// 获得网络资源的输入流对象
            BufferedInputStream bin = new BufferedInputStream(in);// 创建输入缓冲流对象
            byte[] buff = new byte[2048];// 创建字节数组
            int len = -1;// 声明存放读取字节数的变量
            len=bin.read(buff);// 读取到内容并添加到字节数组
            while (len!=-1){
                out.write(buff,0,len);// 写入磁盘文件
                len=bin.read(buff);// 读取到内容并添加到字节数组
            }
            out.close();// 关闭流
            bin.close();// 关闭流
            conn.disconnect();// 断开连接
        }catch(Exception ex) {
            JOptionPane.showMessageDialog(null, ex.getMessage());
        }
    }
}


MultiThreadDownFrame

package com.xiaoxuzhu;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

/**
 * Description: 
 *
 * @author xiaoxuzhu
 * @version 1.0
 *
 * <pre>
 * 修改记录:
 * 修改后版本	        修改人		修改日期			修改内容
 * 2022/5/24.1	    xiaoxuzhu		2022/5/24		    Create
 * </pre>
 * @date 2022/5/24
 */
public class MultiThreadDownFrame extends JFrame {
    private JTextField tf_address;

    /**
     * Launch the application
     *
     * @param args
     */
    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    MultiThreadDownFrame frame = new MultiThreadDownFrame();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public MultiThreadDownFrame() {
        super();
        getContentPane().setLayout(null);
        setTitle("网络资源的多线程下载");
        setBounds(100, 100, 482, 189);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JButton button = new JButton();
        button.setBounds(10, 95, 106, 28);
        getContentPane().add(button);
        button.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                try {
                    String address = tf_address.getText();// 获得网络资源地址
                    int pos = address.lastIndexOf("/");              // 获得路径中最后一个斜杠的位置
                    String fileName = address.substring(pos+1);      // 截取文件名
                    download(address, "d:\\"+fileName, 2);// 调用download()方法,将下载的网络资源保存到磁盘
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        });
        button.setText("下    载");

        final JLabel label = new JLabel();
        label.setText("网络资源的地址:");
        label.setBounds(10, 44, 106, 18);
        getContentPane().add(label);

        tf_address = new JTextField();
        tf_address.setBounds(114, 42, 341, 22);
        getContentPane().add(tf_address);

        final JButton button_1 = new JButton();
        button_1.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                tf_address.setText(null);
            }
        });
        button_1.setText("清    空");
        button_1.setBounds(179, 95, 106, 28);
        getContentPane().add(button_1);

        final JButton button_2 = new JButton();
        button_2.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                System.exit(0);
            }
        });
        button_2.setText("退    出");
        button_2.setBounds(349, 95, 106, 28);
        getContentPane().add(button_2);
    }

    public void download(String url, String dest, int threadNum)
            throws Exception {
        URL downURL = new URL(url);// 创建网络资源的URL
        HttpURLConnection conn = (HttpURLConnection) downURL.openConnection();// 打开网络边接
        long fileLength = -1;// 用于存储文件长度的变量
        int stateFlagCode = conn.getResponseCode();// 获得连接状态标记代码
        if (stateFlagCode == 200) {// 网络连接正常
            fileLength = conn.getContentLength();// 获得文件的长度
            conn.disconnect();// 取消网络连接
        }
        if (fileLength > 0) {
            long byteCounts = fileLength / threadNum + 1;// 计算每个线程的字节数
            File file = new File(dest);// 创建目标文件的File对象
            int i = 0;
            while (i < threadNum) {
                long startPosition = byteCounts * i;// 定义开始位置
                long endPosition = byteCounts * (i + 1);// 定义结束位置
                if (i == threadNum - 1) {
                    DownMultiThread fileThread = new DownMultiThread(url, file,
                            startPosition, 0);// 创建DownMultiThread线程的实例
                    new Thread(fileThread).start();// 启动线程对象
                } else {
                    DownMultiThread fileThread = new DownMultiThread(url, file,
                            startPosition, endPosition);// 创建DownMultiThread线程的实例
                    new Thread(fileThread).start();// 启动线程对象
                }
                i++;
            }
            JOptionPane.showMessageDialog(null, "完成网络资源的下载。");
        }
    }
}

下载速度提高不少。

如图

可以找大文件自己下载试试

四、推荐专栏

《JAVA从零到壹》

《JAVA筑基100例》

五、示例源码下载

关注下面的公众号,回复筑基+题目号

筑基85

文章来源: xiaoxuzhu.blog.csdn.net,作者:小虚竹,版权归原作者所有,如需转载,请联系作者。

原文链接:xiaoxuzhu.blog.csdn.net/article/details/125238517

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。