《安卓网络编程》之第四篇 处理URL地址

  在Android手机系统中,可以通过URL地址获取网络资源。在URL类的众多方法中,可以使用openStream()方法来读取该URL资源的输入流InputStream。在此方法的基础上可以引申出很多重要的应用。在URL中,可以使用方法openConnection()返回一个URLConnection对象,该对象表示应用程序和URL之间的通信连接。程序可以通过URLConnection实例向该URL发送请求、读取URL引用的资源。

下面的例子是在JAVA环境下使用URL实现多线程下载:

多线程类DownTHhread

 1 import java.io.*;
 2 
 3 //定义下载从start到end的内容的线程
 4 class DownThread extends Thread {
 5     // 定义字节数组(取水的竹筒)的长度
 6     private final int BUFF_LEN = 32;
 7     // 定义下载的起始点
 8     private long start;
 9     // 定义下载的结束点
10     private long end;
11     // 下载资源对应的输入流
12     private InputStream is;
13     // 将下载到的字节输出到raf中
14     private RandomAccessFile raf;
15     
16     // 构造器,传入输入流,输出流和下载起始点、结束点
17     public DownThread(long start, long end, InputStream is, RandomAccessFile raf) {
18         // 输出该线程负责下载的字节位置
19         System.out.println(start + "---->" + end);
20         this.start = start;
21         this.end = end;
22         this.is = is;
23         this.raf = raf;    
24     }
25 
26     public void run() {
27         try {
28             is.skip(start);
29             raf.seek(start);
30             // 定义读取输入流内容的缓存数组(竹筒)
31             byte[] buff = new byte[BUFF_LEN];
32             // 本线程负责下载资源的大小
33             long contentLen = end - start;
34             // 定义最多需要读取几次就可以完成本线程的下载
35             long times = contentLen / BUFF_LEN + 4;
36             // 实际读取的字节数
37             int hasRead = 0;
38             for (int i = 0; i < times; i++) {
39                 hasRead = is.read(buff);
40                 // 如果读取的字节数小于0,则退出循环!
41                 if (hasRead < 0) {
42                     break;
43                 }
44                 raf.write(buff, 0, hasRead);
45             }
46         } catch (Exception ex) {
47             ex.printStackTrace();
48         }
49         // 使用finally块来关闭当前线程的输入流、输出流
50         finally {
51             try {
52                 if (is != null) {
53                     is.close();
54                 }
55                 if (raf != null) {
56                     raf.close();
57                 }
58             } catch (Exception ex) {
59                 ex.printStackTrace();
60             }
61         }
62     }
63 }

类MutilDown:

 1 import java.io.*;
 2 import java.net.*;
 3 
 4 public class MutilDown {
 5     public static void main(String[] args) {
 6         final int DOWN_THREAD_NUM = 4;
 7         final String OUT_FILE_NAME = "down.jpg";
 8         InputStream[] isArr = new InputStream[DOWN_THREAD_NUM];
 9         RandomAccessFile[] outArr = new RandomAccessFile[DOWN_THREAD_NUM];
10         try {
11             // 创建一个URL对象
12             URL url = new URL("http://images.china-pub.com/"
13                     + "ebook35001-40000/35850/shupi.jpg");
14             // 以此URL对象打开第一个输入流
15             isArr[0] = url.openStream();
16             long fileLen = getFileLength(url);
17             System.out.println("网络资源的大小" + fileLen);
18             // 以输出文件名创建第一个RandomAccessFile输出流
19             outArr[0] = new RandomAccessFile(OUT_FILE_NAME, "rw");
20             // 创建一个与下载资源相同大小的空文件
21             for (int i = 0; i < fileLen; i++) {
22                 outArr[0].write(0);
23             }
24             // 每线程应该下载的字节数
25             long numPerThred = fileLen / DOWN_THREAD_NUM;
26             // 整个下载资源整除后剩下的余数
27             long left = fileLen % DOWN_THREAD_NUM;
28             for (int i = 0; i < DOWN_THREAD_NUM; i++) {
29                 // 为每个线程打开一个输入流、一个RandomAccessFile对象,
30                 // 让每个线程分别负责下载资源的不同部分。
31                 if (i != 0) {
32                     // 以URL打开多个输入流
33                     isArr[i] = url.openStream();
34                     // 以指定输出文件创建多个RandomAccessFile对象
35                     outArr[i] = new RandomAccessFile(OUT_FILE_NAME, "rw");
36                 }
37                 // 分别启动多个线程来下载网络资源
38                 if (i == DOWN_THREAD_NUM - 1) {
39                     // 最后一个线程下载指定numPerThred+left个字节
40                     new DownThread(i * numPerThred, (i + 1) * numPerThred
41                             + left, isArr[i], outArr[i]).start();
42                 } else {
43                     // 每个线程负责下载一定的numPerThred个字节
44                     new DownThread(i * numPerThred, (i + 1) * numPerThred,
45                             isArr[i], outArr[i]).start();
46                 }
47             }
48         } catch (Exception ex) {
49             ex.printStackTrace();
50         }
51     }
52 
53     // 定义获取指定网络资源的长度的方法
54     // 定义获取指定网络资源的长度的方法
55     public static long getFileLength(URL url) throws Exception {
56         long length = 0;
57         // 打开该URL对应的URLConnection。
58         URLConnection con = url.openConnection();
59         // 获取连接URL资源的长度
60         long size = con.getContentLength();
61         length = size;
62         return length;
63     }
64 }

上面的代码中类MutilDown按如下步骤实现多线程下载:

  1. 创建URL对象。
  2. 获取指定URL对象所指向资源的大小(由getFileLength方法实现),此处用到了URLConnection类,该类代表Java应用程序和URL之间的通信链接。
  3. 在本地磁盘上创建一个与网络资源相同大小的空文件。
  4. 计算每条线程应该下载网络资源的哪个部分(从哪个字节开始,到哪个字节结束)。
  5. 依次创建、启动多条线程来下载网络资源的指定部分。

程序运行结果:

网络资源的大小69281
0---->17320
17320---->34640
34640---->51960
51960---->69281

工程对应目录会出现down.jpg

posted @ 2015-03-25 14:55  疾风剑  阅读(301)  评论(0编辑  收藏  举报