原文章地址:http://androidguy.blog.51cto.com/974126/214410
源代码下载:http://files.cnblogs.com/nokiaguy/download.rar
在前面的文章曾讨论了HTTP消息头的三个和断点继传有关的字段。一个是请求消息的字段Range,另两个是响应消息字段Accept-Ranges和Content-Range。其中Accept-Ranges用来断定Web服务器是否支持断点继传功能。在这里为了演示如何实现断点继传功能,假设Web服务器支持这个功能;因此,我们只使用Range和Content-Range来完成一个断点继传工具的开发。
http://www.ishare.cc/d/1174292-2/156.jpg d:\ok2.jpg 12345
http://www.ishare.cc/d/1174277-2/147.jpg d:\ok3.jpg 3456
- 要下载的Web资源的URL。
- 要保存的本地文件名。
- 下载的缓冲区大小(单位是字节)。
public interface DownloadEvent
{
void percent(long n); // 下载进度
void state(String s); // 连接过程中的状态切换
void viewHttpHeaders(String s); // 枚举每一个响应消息字段
}
002
003 import java.net.*;
004 import java.io.*;
005 import java.util.*;
006
007 public class HttpDownload
008 {
009 private HashMap httpHeaders = new HashMap();
010 private String stateCode;
011
012 // generateHttpRequest方法
013
014 /* ananlyzeHttpHeader方法
015 *
016 * addHeaderToMap方法
017 *
018 * analyzeFirstLine方法
019 */
020
021 // getFileSize方法
022
023 // download方法
024
025 /* getHeader方法
026 *
027 * getIntHeader方法
028 */
029 }
002 String path, long startPos) throws IOException
003 {
004 OutputStreamWriter writer = new OutputStreamWriter(out);
005 writer.write("GET " + path + " HTTP/1.1\r\n");
006 writer.write("Host: " + host + "\r\n");
007 writer.write("Accept: */*\r\n");
008 writer.write("User-Agent: My First Http Download\r\n");
009 if (startPos > 0) // 如果是断点续传,加入Range字段
010 writer.write("Range: bytes=" + String.valueOf(startPos) + "-\r\n");
011 writer.write("Connection: close\r\n\r\n");
012 writer.flush();
013 }
002 throws Exception
003 {
004 String s = "";
005 byte b = -1;
006 while (true)
007 {
008 b = (byte) inputStream.read();
009 if (b == '\r')
010 {
011 b = (byte) inputStream.read();
012 if (b == '\n')
013 {
014 if (s.equals(""))
015 break;
016 de.viewHttpHeaders(s);
017 addHeaderToMap(s);
018 s = "";
019 }
020 }
021 else
022 s += (char) b;
023 }
024 }
025
026 private void analyzeFirstLine(String s)
027 {
028 String[] ss = s.split("[ ]+");
029 if (ss.length > 1)
030 stateCode = ss[1];
031 }
032 private void addHeaderToMap(String s)
033 {
034 int index = s.indexOf(":");
035 if (index > 0)
036 httpHeaders.put(s.substring(0, index), s.substring(index + 1) .trim());
037 else
038 analyzeFirstLine(s);
039 }
002 {
003 return (String) httpHeaders.get(header);
004 }
005 private int getIntHeader(String header)
006 {
007 return Integer.parseInt(getHeader(header));
008 }
002 {
003 long length = -1;
004 try
005 {
006 length = getIntHeader("Content-Length");
007 String[] ss = getHeader("Content-Range").split("[/]");
008 if (ss.length > 1)
009 length = Integer.parseInt(ss[1]);
010 else
011 length = -1;
012 }
013 catch (Exception e)
014 {
015 }
016 return length;
017 }
002 int cacheSize) throws Exception
003 {
004 File file = new File(localFN);
005 long finishedSize = 0;
006 long fileSize = 0; // localFN所指的文件的实际大小
007 FileOutputStream fileOut = new FileOutputStream(localFN, true);
008 URL myUrl = new URL(url);
009 Socket socket = new Socket();
010 byte[] buffer = new byte[cacheSize]; // 下载数据的缓冲
011
012 if (file.exists())
013 finishedSize = file.length();
014
015 // 得到要下载的Web资源的端口号,未提供,默认是80
016 int port = (myUrl.getPort() == -1) ? 80 : myUrl.getPort();
017 de.state("正在连接" + myUrl.getHost() + ":" + String.valueOf(port));
018 socket.connect(new InetSocketAddress(myUrl.getHost(), port), 20000);
019 de.state("连接成功!");
020
021 // 产生HTTP请求消息
022 generateHttpRequest(socket.getOutputStream(), myUrl.getHost(), myUrl
023 .getPath(), finishedSize);
024
025 InputStream inputStream = socket.getInputStream();
026 // 分析HTTP响应消息头
027 analyzeHttpHeader(inputStream, de);
028 fileSize = getFileSize(); // 得到下载文件的实际大小
029 if (finishedSize >= fileSize)
030 return;
031 else
032 {
033 if (finishedSize > 0 && stateCode.equals("200"))
034 return;
035 }
036 if (stateCode.charAt(0) != '2')
037 throw new Exception("不支持的响应码");
038 int n = 0;
039 long m = finishedSize;
040 while ((n = inputStream.read(buffer)) != -1)
041 {
042 fileOut.write(buffer, 0, n);
043 m += n;
044 if (fileSize != -1)
045 {
046 de.percent(m * 100 / fileSize);
047 }
048 }
049 fileOut.close();
050 socket.close();
051 }
002
003 import java.io.*;
004
005 class NewProgress implements DownloadEvent
006 {
007 private long oldPercent = -1;
008 public void percent(long n)
009 {
010 if (n > oldPercent)
011 {
012 System.out.print("[" + String.valueOf(n) + "%]");
013 oldPercent = n;
014 }
015 }
016 public void state(String s)
017 {
018 System.out.println(s);
019 }
020 public void viewHttpHeaders(String s)
021 {
022 System.out.println(s);
023 }
024 }
025
026 public class Main
027 {
028 public static void main(String[] args) throws Exception
029 {
030
031 DownloadEvent progress = new NewProgress();
032 if (args.length < 1)
033 {
034 System.out.println("用法:java class 下载文件名");
035 return;
036 }
037 FileInputStream fis = new FileInputStream(args[0]);
038 BufferedReader fileReader = new BufferedReader(new InputStreamReader(
039 fis));
040 String s = "";
041 String[] ss;
042 while ((s = fileReader.readLine()) != null)
043 {
044 try
045 {
046 ss = s.split("[ ]+");
047 if (ss.length > 2)
048 {
049 System.out.println("\r\n---------------------------");
050 System.out.println("正在下载:" + ss[0]);
051 System.out.println("文件保存位置:" + ss[1]);
052 System.out.println("下载缓冲区大小:" + ss[2]);
053 System.out.println("---------------------------");
054 HttpDownload httpDownload = new HttpDownload();
055 httpDownload.download(new NewProgress(), ss[0], ss[1],
056 Integer.parseInt(ss[2]));
057 }
058 }
059 catch (Exception e)
060 {
061 System.out.println(e.getMessage());
062 }
063 }
064 fileReader.close();
065 }
066 }
http://files.cnblogs.com/nokiaguy/designpatterns.rar designpatterns.rar 4096
http://files.cnblogs.com/nokiaguy/download.rar download.rar 8192