(1) หลักการของการดาวน์โหลดต่อ <BR>อันที่จริง หลักการของการดาวน์โหลดต่อนั้นง่ายมาก เพียงแต่ว่าคำขอ HTTP นั้นแตกต่างจากการดาวน์โหลดทั่วไป
ตัวอย่างเช่น เมื่อเบราว์เซอร์ร้องขอไฟล์บนเซิร์ฟเวอร์ คำขอที่เบราว์เซอร์ทำจะเป็นดังนี้:
สมมติว่าชื่อโดเมนเซิร์ฟเวอร์คือ wwww.sjtu.edu.cn และชื่อไฟล์คือ down.zip
รับ /down.zip HTTP/1.1
ยอมรับ: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-
excel, แอปพลิเคชัน/msword, แอปพลิเคชัน/vnd.ms-powerpoint, */*
ยอมรับ-ภาษา: zh-cn
ยอมรับการเข้ารหัส: gzip, deflate
ตัวแทนผู้ใช้: Mozilla/4.0 (เข้ากันได้; MSIE 5.01; Windows NT 5.0)
การเชื่อมต่อ: Keep-Alive
หลังจากที่เซิร์ฟเวอร์ได้รับคำขอแล้ว จะค้นหาไฟล์ที่ร้องขอตามต้องการ แยกข้อมูลไฟล์ จากนั้นส่งคืนไปยังเบราว์เซอร์ ข้อมูลที่ส่งคืนจะเป็นดังนี้
200
ความยาวเนื้อหา=106786028
ยอมรับ-ช่วง=ไบต์
วันที่=จันทร์ 30 เมษายน 2544 12:56:11 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
เซิร์ฟเวอร์=Microsoft-IIS/5.0
Last-Modified=จันทร์ที่ 30 เมษายน 2544 12:56:11 GMT
สิ่งที่เรียกว่าการดาวน์โหลดประวัติย่อหมายถึงการดาวน์โหลดต่อจากจุดที่ดาวน์โหลดไฟล์ไปแล้ว ดังนั้นในเบราว์เซอร์ไคลเอนต์ผ่าน
เมื่อพูดถึงเว็บเซิร์ฟเวอร์ จำเป็นต้องเพิ่มข้อมูลอีกหนึ่งชิ้น - จะเริ่มต้นจากที่ใด
ต่อไปนี้เป็น "เบราว์เซอร์" ที่รวบรวมโดยตัวเองเพื่อส่งข้อมูลคำขอไปยังเว็บเซิร์ฟเวอร์ คำขอเริ่มต้นจาก 2000070 ไบต์
รับ /down.zip HTTP/1.0
ตัวแทนผู้ใช้: NetFox
ช่วง: ไบต์=2000070-
ยอมรับ: ข้อความ/html, รูปภาพ/gif, รูปภาพ/jpeg, *; q=.2, */*;
หากคุณดูดีๆ คุณจะพบบรรทัดเพิ่มเติมของ RANGE: bytes=2000070-
ความหมายของบรรทัดนี้คือการบอกเซิร์ฟเวอร์ว่าไฟล์ down.zip จะถูกส่งโดยเริ่มจาก 2000070 ไบต์ และไม่จำเป็นต้องส่งไบต์ก่อนหน้า
หลังจากที่เซิร์ฟเวอร์ได้รับการร้องขอนี้ ข้อมูลที่ส่งคืนจะเป็นดังนี้:
206
ความยาวเนื้อหา=106786028
ช่วงเนื้อหา=ไบต์ 2000070-106786027/106786028
วันที่=จันทร์ที่ 30 เมษายน 2544 12:55:20 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
เซิร์ฟเวอร์=Microsoft-IIS/5.0
Last-Modified=จันทร์ที่ 30 เมษายน 2544 12:55:20 GMT
เมื่อเปรียบเทียบกับข้อมูลที่ส่งคืนโดยเซิร์ฟเวอร์ก่อนหน้า คุณจะพบว่ามีการเพิ่มบรรทัด:
ช่วงเนื้อหา=ไบต์ 2000070-106786027/106786028
รหัสส่งคืนก็เปลี่ยนเป็น 206 แทนที่จะเป็น 200
เมื่อทราบหลักการข้างต้นแล้ว คุณสามารถตั้งโปรแกรมการดาวน์โหลดเบรกพอยต์ต่อได้
(2) ประเด็นสำคัญในการใช้การถ่ายโอนประวัติเบรกพอยต์ใน Java
(1) วิธีใดที่ใช้ในการส่ง RANGE: bytes=2000070-
แน่นอนว่าสามารถทำได้โดยใช้ Socket ดั้งเดิม แต่นั่นคงลำบากเกินไป จริงๆ แล้ว net package ของ Java มีฟังก์ชันนี้มาให้ รหัสมีดังนี้:
URL URL = URL ใหม่ ("http://www.sjtu.edu.cn/down.zip");
HttpURLConnection httpConnection = (การเชื่อมต่อ HttpURL)url.openConnection();
//ตั้งค่าตัวแทนผู้ใช้
httpConnection.setRequestProperty("ตัวแทนผู้ใช้", "NetFox");
//กำหนดตำแหน่งเริ่มต้นของการส่งข้อมูลเบรกพอยต์ต่อ
httpConnection.setRequestProperty("RANGE", "bytes=2000070");
//รับอินพุตสตรีม
อินพุต InputStream = httpConnection.getInputStream();
ไบต์สตรีมที่นำออกจากสตรีมอินพุตคือสตรีมไบต์ที่เริ่มต้นจาก 2000070 ในไฟล์ down.zip
คุณจะเห็นว่าจริง ๆ แล้วมันเป็นเรื่องง่ายมากที่จะใช้การถ่ายโอนเรซูเม่เบรกพอยต์ใน Java
สิ่งต่อไปที่ต้องทำคือวิธีบันทึกสตรีมที่ได้รับลงในไฟล์
วิธีที่ใช้ในการบันทึกไฟล์
ฉันใช้คลาส RandAccessFile ในแพ็คเกจ IO
การดำเนินการค่อนข้างง่าย สมมติว่าไฟล์ถูกบันทึกโดยเริ่มจาก 2000070 รหัสจะเป็นดังนี้:
คัดลอกรหัสรหัส ดังต่อไปนี้:
RandomAccess oSavedFile = new RandomAccessFile("down.zip", "rw");
nPos ยาว = 2000070;
//ค้นหาตำแหน่งตัวชี้ไฟล์ไปยังตำแหน่ง nPos
oSavedFile.seek(nPos);
ไบต์ [] b = ไบต์ใหม่ [1024];
int nRead;
//อ่านไบต์สตรีมจากอินพุตสตรีมและเขียนลงในไฟล์
ในขณะที่((nRead=input.read(b,0,1024)) > 0)
-
oSavedFile.write(b,0,nอ่าน);
-
อย่างไรก็ตามมันง่ายมาก
สิ่งต่อไปที่ต้องทำคือการรวมเข้ากับโปรแกรมที่สมบูรณ์ รวมถึงชุดควบคุมเธรดเป็นต้น
(3) การใช้งานเคอร์เนลเบรกพอยต์ดำเนินการต่อ <BR>ส่วนใหญ่ใช้ 6 คลาส รวมถึงคลาสทดสอบด้วย
SiteFileFetch.java มีหน้าที่รับผิดชอบในการดึงไฟล์ทั้งหมดและควบคุมเธรดภายใน (คลาส FileSplitterFetch)
FileSplitterFetch.java มีหน้าที่ดึงไฟล์บางไฟล์
FileAccess.java มีหน้าที่จัดเก็บไฟล์
ข้อมูลเกี่ยวกับไฟล์ที่ SiteInfoBean.java ต้องการรวบรวมข้อมูล เช่น ไดเร็กทอรีที่บันทึกไฟล์ ชื่อไฟล์ URL ของไฟล์ที่รวบรวมข้อมูล เป็นต้น
คลาสเครื่องมือ Utility.java ใส่วิธีการง่ายๆ
คลาสทดสอบ TestMethod.java
ต่อไปนี้เป็นโปรแกรมต้นทาง:
คัดลอกรหัสรหัส ดังต่อไปนี้:
-
**SiteFileFetch.java
-
แพ็คเกจ NetFox;
นำเข้า java.io.*;
นำเข้า java.net.*;
SiteFileFetch ระดับสาธารณะขยายเธรด {
SiteInfoBean siteInfoBean = null; // ข้อมูลไฟล์ Bean
ยาว [] nStartPos; // ตำแหน่งเริ่มต้น
long[] nEndPos; //ตำแหน่งสิ้นสุด
FileSplitterFetch[] fileSplitterFetch; //วัตถุเธรดย่อย
long nFileLength; // ความยาวไฟล์
boolean bFirst = true; // ว่าจะดึงไฟล์เป็นครั้งแรกหรือไม่
บูลีน bStop = false; //เครื่องหมายหยุด
ไฟล์ tmpFile; //ข้อมูลชั่วคราวสำหรับการดาวน์โหลดไฟล์
DataOutputStream เอาท์พุต; //เอาท์พุตสตรีมไปยังไฟล์
SiteFileFetch สาธารณะ (SiteInfoBean bean) พ่น IOException
-
siteInfoBean = ถั่ว;
//tmpFile = File.createTempFile ("zhong", "1111",ไฟล์ใหม่(bean.getSFilePath()));
tmpFile = ไฟล์ใหม่ (bean.getSFilePath()+File.separator + bean.getSFileName()+".info");
ถ้า (tmpFile.exists ())
-
ขแรก = เท็จ;
read_nPos();
-
อื่น
-
nStartPos = ใหม่ยาว[bean.getNSplitter()];
nEndPos = ใหม่ยาว[bean.getNSplitter()];
-
-
การรันโมฆะสาธารณะ ()
-
//รับความยาวไฟล์
//แยกไฟล์
//อินสแตนซ์ FileSplitterFetch
//เริ่มเธรด FileSplitterFetch
//รอให้เธรดย่อยกลับมา
พยายาม{
ถ้า(ขแรก)
-
nFileLength = getFileSize();
ถ้า (nFileLength == -1)
-
System.err.println("ไม่ทราบความยาวไฟล์!");
-
อย่างอื่นถ้า (nFileLength == -2)
-
System.err.println("ไฟล์ไม่สามารถเข้าถึงได้!");
-
อื่น
-
สำหรับ(int i=0;i<nStartPos.length;i++)
-
nStartPos[i] = (ยาว)(i*(nFileLength/nStartPos.length));
-
สำหรับ(int i=0;i<nEndPos.length-1;i++)
-
nEndPos[i] = nStartPos[i+1];
-
nEndPos[nEndPos.length-1] = nFileLength;
-
-
//เริ่มเธรดย่อย
fileSplitterFetch = FileSplitterFetch ใหม่ [nStartPos.length];
สำหรับ(int i=0;i<nStartPos.length;i++)
-
fileSplitterFetch[i] = FileSplitterFetch ใหม่ (siteInfoBean.getSSiteURL(),
siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName()
nStartPos[i],nEndPos[i],ฉัน);
Utility.log("เธรด " + i + " , nStartPos = " + nStartPos[i] + ", nEndPos = " + nEndPos[i]);
fileSplitterFetch[i].เริ่มต้น();
-
// fileSplitterFetch[nPos.length-1] = ใหม่ FileSplitterFetch(siteInfoBean.getSSiteURL(),
siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(),nPos[nPos.length-1],nFileLength,nPos.length-1);
// Utility.log("Thread " + (nPos.length-1) + " , nStartPos = " + nPos[nPos.length-1] + ",
nEndPos = " + nFileLength);
// fileSplitterFetch[nPos.length-1].start();
//รอให้เธรดย่อยสิ้นสุด
//จำนวน int = 0;
//ว่าจะจบ while loop หรือไม่
บูลีน breakWhile = false;
ในขณะที่(!bStop)
-
write_nPos();
Utility.sleep (500);
แบ่งขณะ = จริง;
สำหรับ(int i=0;i<nStartPos.length;i++)
-
ถ้า(!fileSplitterFetch[i].bDownOver)
-
breakWhile = เท็จ;
หยุดพัก;
-
-
ถ้า (breakWhile)
หยุดพัก;
//นับ++;
//ถ้า(นับ>4)
// siteStop();
-
System.err.println("ดาวน์โหลดไฟล์เสร็จสิ้น!");
-
catch (ข้อยกเว้น e) {e.printStackTrace ();}
-
//รับความยาวไฟล์
getFileSize ยาวสาธารณะ ()
-
int nFileLength = -1;
พยายาม{
URL url = URL ใหม่ (siteInfoBean.getSSiteURL());
HttpURLConnection httpConnection = (การเชื่อมต่อ HttpURL)url.openConnection ();
httpConnection.setRequestProperty("ตัวแทนผู้ใช้", "NetFox");
int responseCode=httpConnection.getResponseCode();
ถ้า(รหัสตอบกลับ>=400)
-
กระบวนการรหัสข้อผิดพลาด (รหัสตอบกลับ);
return -2; //-2 หมายถึงการเข้าถึงมีข้อผิดพลาด
-
สตริง sHeader;
สำหรับ (int i = 1;; i ++)
-
//DataInputStream ใน = DataInputStream ใหม่ (httpConnection.getInputStream ());
//Utility.log(in.readLine());
sHeader=httpConnection.getHeaderFieldKey(i);
ถ้า(sHeader!=null)
-
if(sHeader.equals("เนื้อหาความยาว"))
-
nFileLength = Integer.parseInt(httpConnection.getHeaderField(sHeader));
หยุดพัก;
-
-
อื่น
หยุดพัก;
-
-
จับ (IOException e) {e.printStackTrace ();}
catch (ข้อยกเว้น e) {e.printStackTrace ();}
Utility.log(nFileLength);
กลับ nFileLength;
-
//บันทึกข้อมูลการดาวน์โหลด (ตำแหน่งตัวชี้ไฟล์)
โมฆะส่วนตัว write_nPos ()
-
พยายาม{
เอาท์พุท = DataOutputStream ใหม่ (FileOutputStream ใหม่ (tmpFile));
output.writeInt(nStartPos.ความยาว);
สำหรับ(int i=0;i<nStartPos.length;i++)
-
// output.writeLong(nPos[i]);
output.writeLong(fileSplitterFetch[i].nStartPos);
output.writeLong(fileSplitterFetch[i].nEndPos);
-
เอาท์พุท.ปิด();
-
จับ (IOException e) {e.printStackTrace ();}
catch (ข้อยกเว้น e) {e.printStackTrace ();}
-
//อ่านข้อมูลการดาวน์โหลดที่บันทึกไว้ (ตำแหน่งตัวชี้ไฟล์)
โมฆะส่วนตัว read_nPos()
-
พยายาม{
อินพุต DataInputStream = DataInputStream ใหม่ (FileInputStream ใหม่ (tmpFile));
int nCount = input.readInt();
nStartPos = ใหม่ยาว[nCount];
nEndPos = ใหม่ยาว[nCount];
สำหรับ(int i=0;i<nStartPos.length;i++)
-
nStartPos[i] = input.readLong();
nEndPos[i] = input.readLong();
-
อินพุต.ปิด();
-
จับ (IOException e) {e.printStackTrace ();}
catch (ข้อยกเว้น e) {e.printStackTrace ();}
-
กระบวนการโมฆะส่วนตัวErrorCode (int nErrorCode)
-
System.err.println("รหัสข้อผิดพลาด : " + nErrorCode);
-
//หยุดดาวน์โหลดไฟล์
โมฆะสาธารณะ siteStop()
-
bStop = จริง;
สำหรับ(int i=0;i<nStartPos.length;i++)
fileSplitterFetch[i].splitterStop();
-
-
-
**FileSplitterFetch.java
-
แพ็คเกจ NetFox;
นำเข้า java.io.*;
นำเข้า java.net.*;
FileSplitterFetch คลาสสาธารณะขยายเธรด {
สตริง sURL; //URL ของไฟล์
long nStartPos; // ตำแหน่งเริ่มต้นของตัวอย่างไฟล์
long nEndPos; // ตำแหน่งสิ้นสุดตัวอย่างไฟล์
int nThreadID; // ID ของเธรด
boolean bDownOver = false; // Downing จบลงแล้ว
บูลีน bStop = false; //หยุดเหมือนกัน
FileAccessI fileAccessI = null; // อินเทอร์เฟซการเข้าถึงไฟล์
FileSplitterFetch สาธารณะ (String sURL, String sName, nStart แบบยาว, nEnd แบบยาว, int id) พ่น IOException
-
นี้.sURL = sURL;
this.nStartPos = nStart;
this.nEndPos = nEnd;
nThreadID = รหัส;
fileAccessI = FileAccessI ใหม่ (sName, nStartPos);
-
การรันโมฆะสาธารณะ ()
-
ในขณะที่(nStartPos < nEndPos && !bStop)
-
พยายาม{
URL URL = URL ใหม่(sURL);
HttpURLConnection httpConnection = (การเชื่อมต่อ HttpURL)url.openConnection ();
httpConnection.setRequestProperty("ตัวแทนผู้ใช้", "NetFox");
สตริง sProperty = "bytes="+nStartPos+"-";
httpConnection.setRequestProperty("RANGE",sProperty);
Utility.log(sคุณสมบัติ);
อินพุต InputStream = httpConnection.getInputStream();
//logResponseHead(httpการเชื่อมต่อ);
ไบต์ [] b = ไบต์ใหม่ [1024];
int nRead;
ในขณะที่((nRead=input.read(b,0,1024)) > 0 && nStartPos < nEndPos && !bStop)
-
nStartPos += fileAccessI.write(b,0,nRead);
//ถ้า(nThreadID == 1)
// Utility.log("nStartPos = " + nStartPos + ", nEndPos = " + nEndPos);
-
Utility.log("Thread " + nThreadID + " จบแล้ว!");
bDownOver = จริง;
//nPos = fileAccessI.write (b,0,nRead);
-
catch (ข้อยกเว้น e) {e.printStackTrace ();}
-
-
//พิมพ์ข้อมูลส่วนหัวของคำตอบ
โมฆะสาธารณะ logResponseHead (HttpURLConnection con)
-
สำหรับ (int i = 1;; i ++)
-
ส่วนหัวของสตริง=con.getHeaderFieldKey(i);
ถ้า(ส่วนหัว!=null)
//responseHeaders.put(ส่วนหัว,httpConnection.getHeaderField(ส่วนหัว));
Utility.log(header+" : "+con.getHeaderField(ส่วนหัว));
อื่น
หยุดพัก;
-
-
โมฆะสาธารณะ splitterStop()
-
bStop = จริง;
-
-
-
**FileAccess.java
-
แพ็คเกจ NetFox;
นำเข้า java.io.*;
FileAccessI คลาสสาธารณะใช้ Serializable {
RandomAccessFile oSavedFile;
nPos ยาว;
FileAccessI() สาธารณะพ่น IOException
-
นี้("",0);
-
FileAccessI สาธารณะ (ชื่อสตริง, nPos แบบยาว) พ่น IOException
-
oSavedFile = RandomAccessFile ใหม่ (sName, "rw");
นี่.nPos = nPos;
oSavedFile.seek(nPos);
-
การซิงโครไนซ์สาธารณะ int write (ไบต์ [] b, int nStart, int nLen)
-
อินท์ n = -1;
พยายาม{
oSavedFile.write(b,nStart,nLen);
n = nเลน;
-
จับ (IOException e)
-
e.printStackTrace();
-
กลับ n;
-
-
-
**SiteInfoBean.java
-
แพ็คเกจ NetFox;
SiteInfoBean ระดับสาธารณะ {
สตริงส่วนตัว sSiteURL; //URL ของไซต์
สตริงส่วนตัว sFilePath; //เส้นทางของไฟล์ที่บันทึกไว้
สตริงส่วนตัว sFileName; //ชื่อไฟล์ที่บันทึกไว้
private int nSplitter; // จำนวนไฟล์ที่ดาวน์โหลดแบบแยกส่วน
SiteInfoBean สาธารณะ ()
-
//ค่าเริ่มต้นของ nSplitter คือ 5
นี้("", "",5);
-
SiteInfoBean สาธารณะ (สตริง sURL, สตริง sPath, สตริง sName, int nSpiltter)
-
sSiteURL= sURL;
sFilePath = สพาธ;
sFileName = sName;
this.nSplitter = nSpiltter;
-
สตริงสาธารณะ getSSiteURL()
-
ส่งคืน sSiteURL;
-
โมฆะสาธารณะ setSSiteURL (ค่าสตริง)
-
sSiteURL = ค่า;
-
สตริงสาธารณะ getSFilePath()
-
กลับ sFilePath;
-
โมฆะสาธารณะ setSFilePath (ค่าสตริง)
-
sFilePath = ค่า;
-
สตริงสาธารณะ getSFileName()
-
กลับ sFileName;
-
โมฆะสาธารณะ setSFileName (ค่าสตริง)
-
sFileName = ค่า;
-
สาธารณะ int getNSplitter()
-
กลับ nSplitter;
-
โมฆะสาธารณะ setNSplitter (int nCount)
-
nSplitter = nนับ;
-
-
-
**ยูทิลิตี้.java
-
แพ็คเกจ NetFox;
ยูทิลิตี้คลาสสาธารณะ {
สาธารณูปโภค()
-
-
การนอนหลับเป็นโมฆะสาธารณะแบบคงที่ (int nSecond)
-
พยายาม{
Thread.sleep (nวินาที);
-
จับ (ยกเว้น e)
-
e.printStackTrace();
-
-
บันทึกโมฆะคงที่สาธารณะ (String sMsg)
-
System.err.println(sMsg);
-
บันทึกโมฆะคงที่สาธารณะ (int sMsg)
-
System.err.println(sMsg);
-
-
-
**TestMethod.java
-
แพ็คเกจ NetFox;
วิธีทดสอบคลาสสาธารณะ {
วิธีทดสอบสาธารณะ ()
{ ///xx/weblogic60b2_win.exe
พยายาม{
SiteInfoBean bean = SiteInfoBean ใหม่ ("http://localhost/xx/weblogic60b2_win.exe", L://temp ", weblogic60b2_win.exe", 5);
//SiteInfoBean bean = SiteInfoBean ใหม่("http://localhost:8080/down.zip","L://temp","weblogic60b2_win.exe",5);
SiteFileFetch fileFetch = ใหม่ SiteFileFetch(bean);
fileFetch.start();
-
จับ (ข้อยกเว้น e) {e.printStackTrace ();
-
-
โมฆะสาธารณะคง main (String [] args)
-
วิธีทดสอบใหม่ ();
-
-