由于網絡傳輸存在著傳輸速度,傳輸路徑等問題,將一個文件分為若干塊來傳送,可以提高傳輸效率,JAVA多線程技術正是將一個任務分為若干個任務來同時完成. 該實例應用JAVA多線程技術,將一個網絡文件分為若干塊,每一個線程負責一塊數據的下載,下載完畢后將其保存在指定的磁盤路徑中. 首先創建繼承Thread類的傳輸文件線程類,其JAVA文件名為SiteFileFetch.java,代碼如下: view plaincopy to clipboardprint?
import java.io.*;
import java.net.*;
public class SiteFileFetch extends Thread { //傳輸文件線程類
SiteInfoBean siteInfoBean=null; //創建文件信息實例
long [] nPos; //文件位置指針
long [] nStartPos; //開始位置
long [] nEndPos; //結束位置
FileSplitterFetch [] fileSplitterFetch; //子線程對象
long nFileLength; //文件長度
boolean bFirst=true; //是否第一次讀取
boolean bStop=false; //停止標志
File tmpFile; //文件傳輸臨時信息
DataOutputStream output; //輸出到文件的輸出流
public SiteFileFetch(SiteInfoBean bean) throws IOException{
siteInfoBean=bean;
tmpFile= new File(bean.getSFilePath()+File.separator+bean.getSFileName()+".info");
if(tmpFile.exists()){
bFirst=false;
read_nPos();
}
else{
nStartPos=new long[bean.getNSplitter()];
nEndPos=new long[bean.getNSplitter()];
}
}
public void run(){
try{
if(bFirst){
nFileLength=getFileSize(); //獲得文件長度
if(nFileLength==-1){
System.err.println("File Length is not known");
}
else
if(nFileLength==-2){
System.err.println("File is not access!");
}
else{
for(int i=0;i<nStartPos.length;i++){ //分割下載文件
nStartPos[i]=(long)(i*(nFileLength/nStartPos.length));
}
for(int i=0;i<nEndPos.length-1;i++){
nEndPos[i]=nStartPos[i+1];
}
nEndPos[nEndPos.length-1]=nFileLength;
}
}
fileSplitterFetch=new FileSplitterFetch[nStartPos.length]; //創建FileSplitterFetch類實例
for(int i=0;i<nStartPos.length;i++){ //啟動FileSplitterFetch線程
fileSplitterFetch[i]=new FileSplitterFetch(siteInfoBean.getSSiteURL(),siteInfoBean.getSFilePath()+File.separator+siteInfoBean.getSFileName(),nStartPos[i],nEndPos[i],i);
Utility.log("Thread "+i+",nStartPos="+nStartPos[i]+" ,nEndPos= "+nEndPos[i]);
fileSplitterFetch[i].start();
}
boolean breakWhile=false;
while(!bStop){ //等待子線程結束
write_nPos();
Utility.sleep(500);
breakWhile=true;
for(int i=0;i<nStartPos.length;i++){
if(!fileSplitterFetch[i].bDownOver){ //等待子線程返回
breakWhile=false;
break;
}
}
if(breakWhile) //是否結束while循環
break;
}
System.out.println("文件傳輸結束!");
}
catch(Exception e){
e.printStackTrace();
}
}
public long getFileSize(){ //獲得文件長度
int nFileLength=-1;
try{ //創建與WEB服務器的連接
URL url=new URL(siteInfoBean.getSSiteURL());
HttpURLConnection httpConnection=(HttpURLConnection)url.openConnection();
httpConnection.setRequestProperty("User-Agent", "NetFox");
int responseCode=httpConnection.getResponseCode();
if(responseCode>=400){
processErrorCode(responseCode);
return -2; //-2為WEB服務器響應錯誤
}
String sHeader;
for(int i=1;;i++){
sHeader=httpConnection.getHeaderFieldKey(i);
if(sHeader!=null){
if(sHeader.equals("Content-Length")){
nFileLength=Integer.parseInt(httpConnection.getHeaderField(sHeader));
break;
}
}
else
break;
}
}
catch(IOException e){
e.printStackTrace();
}
catch(Exception e){
e.printStackTrace();
}
Utility.log(nFileLength);
return nFileLength;
}
private void write_nPos(){ //保存傳輸文件指針位置
try{
output=new DataOutputStream(new FileOutputStream(tmpFile));
output.writeInt(nStartPos.length);
for(int i=0;i<nStartPos.length;i++){
output.writeLong(fileSplitterFetch[i].nStartPos);
output.writeLong(fileSplitterFetch[i].nEndPos);
}
output.close();
}
catch(IOException e){e.printStackTrace();}
catch(Exception e) {e.printStackTrace();}
}
private void read_nPos(){ //讀取保存的下載文件指針位置
try{
DataInputStream input=new DataInputStream(new FileInputStream(tmpFile));
int nCount=input.readInt();
nStartPos=new long[nCount];
nEndPos=new long[nCount];
for(int i=0;i<nStartPos.length;i++){
nStartPos[i]=input.readLong();
nEndPos[i]=input.readLong();
}
input.close();
}
catch(IOException e){e.printStackTrace();}
catch(Exception e) {e.printStackTrace();}
}
private void processErrorCode(int nErrorCode){
System.err.println("Error Code: "+nErrorCode);
}
public void siteStop(){
bStop=true;
for(int i=0;i<nStartPos.length;i++)
fileSplitterFetch[i].splitterStop();
}
}
import java.io.*;
import java.net.*;
public class SiteFileFetch extends Thread { //傳輸文件線程類
SiteInfoBean siteInfoBean=null; //創建文件信息實例
long [] nPos; //文件位置指針
long [] nStartPos; //開始位置
long [] nEndPos; //結束位置
FileSplitterFetch [] fileSplitterFetch; //子線程對象
long nFileLength; //文件長度
boolean bFirst=true; //是否第一次讀取
boolean bStop=false; //停止標志
File tmpFile; //文件傳輸臨時信息
DataOutputStream output; //輸出到文件的輸出流
public SiteFileFetch(SiteInfoBean bean) throws IOException{
siteInfoBean=bean;
tmpFile= new File(bean.getSFilePath()+File.separator+bean.getSFileName()+".info");
if(tmpFile.exists()){
bFirst=false;
read_nPos();
}
else{
nStartPos=new long[bean.getNSplitter()];
nEndPos=new long[bean.getNSplitter()];
}
}
public void run(){
try{
if(bFirst){
nFileLength=getFileSize(); //獲得文件長度
if(nFileLength==-1){
System.err.println("File Length is not known");
}
else
if(nFileLength==-2){
System.err.println("File is not access!");
}
else{
for(int i=0;i<nStartPos.length;i++){ //分割下載文件
nStartPos[i]=(long)(i*(nFileLength/nStartPos.length));
}
for(int i=0;i<nEndPos.length-1;i++){
nEndPos[i]=nStartPos[i+1];
}
nEndPos[nEndPos.length-1]=nFileLength;
}
}
fileSplitterFetch=new FileSplitterFetch[nStartPos.length]; //創建FileSplitterFetch類實例
for(int i=0;i<nStartPos.length;i++){ //啟動FileSplitterFetch線程
fileSplitterFetch[i]=new FileSplitterFetch(siteInfoBean.getSSiteURL(),siteInfoBean.getSFilePath()+File.separator+siteInfoBean.getSFileName(),nStartPos[i],nEndPos[i],i);
Utility.log("Thread "+i+",nStartPos="+nStartPos[i]+" ,nEndPos= "+nEndPos[i]);
fileSplitterFetch[i].start();
}
boolean breakWhile=false;
while(!bStop){ //等待子線程結束
write_nPos();
Utility.sleep(500);
breakWhile=true;
for(int i=0;i<nStartPos.length;i++){
if(!fileSplitterFetch[i].bDownOver){ //等待子線程返回
breakWhile=false;
break;
}
}
if(breakWhile) //是否結束while循環
break;
}
System.out.println("文件傳輸結束!");
}
catch(Exception e){
e.printStackTrace();
}
}
public long getFileSize(){ //獲得文件長度
int nFileLength=-1;
try{ //創建與WEB服務器的連接
URL url=new URL(siteInfoBean.getSSiteURL());
HttpURLConnection httpConnection=(HttpURLConnection)url.openConnection();
httpConnection.setRequestProperty("User-Agent", "NetFox");
int responseCode=httpConnection.getResponseCode();
if(responseCode>=400){
processErrorCode(responseCode);
return -2; //-2為WEB服務器響應錯誤
}
String sHeader;
for(int i=1;;i++){
sHeader=httpConnection.getHeaderFieldKey(i);
if(sHeader!=null){
if(sHeader.equals("Content-Length")){
nFileLength=Integer.parseInt(httpConnection.getHeaderField(sHeader));
break;
}
}
else
break;
}
}
catch(IOException e){
e.printStackTrace();
}
catch(Exception e){
e.printStackTrace();
}
Utility.log(nFileLength);
return nFileLength;
}
private void write_nPos(){ //保存傳輸文件指針位置
try{
output=new DataOutputStream(new FileOutputStream(tmpFile));
output.writeInt(nStartPos.length);
for(int i=0;i<nStartPos.length;i++){
output.writeLong(fileSplitterFetch[i].nStartPos);
output.writeLong(fileSplitterFetch[i].nEndPos);
}
output.close();
}
catch(IOException e){e.printStackTrace();}
catch(Exception e) {e.printStackTrace();}
}
private void read_nPos(){ //讀取保存的下載文件指針位置
try{
DataInputStream input=new DataInputStream(new FileInputStream(tmpFile));
int nCount=input.readInt();
nStartPos=new long[nCount];
nEndPos=new long[nCount];
for(int i=0;i<nStartPos.length;i++){
nStartPos[i]=input.readLong();
nEndPos[i]=input.readLong();
}
input.close();
}
catch(IOException e){e.printStackTrace();}
catch(Exception e) {e.printStackTrace();}
}
private void processErrorCode(int nErrorCode){
System.err.println("Error Code: "+nErrorCode);
}
public void siteStop(){
bStop=true;
for(int i=0;i<nStartPos.length;i++)
fileSplitterFetch[i].splitterStop();
}
}創建繼承Thread類的將要傳輸的網絡文件分割線程類,文件名為FileSplitterFetch.java view plaincopy to clipboardprint?
import java.io.*;
import java.net.*;
public class FileSplitterFetch extends Thread {
String sURL; //定義文件傳輸時使用的變量
long nStartPos; //分段文件傳輸開始位置
long nEndPos; //分段文件傳輸結束位置
int nThreadID; //子線程ID
boolean bDownOver=false; //完成文件傳輸
boolean bStop=false; //停止文件傳輸
FileAccess fileAccess=null;
public FileSplitterFetch(String sURL,String sName,long nStart,long nEnd,int id) throws IOException{
this.sURL=sURL;
this.nStartPos=nStart;
this.nEndPos=nEnd;
nThreadID=id;
fileAccess=new FileAccess(sName,nStartPos); //創建文件并打開
}
public void run(){
while(nStartPos<nEndPos && !bStop){
try{ //創建連接
URL url=new URL(sURL);
HttpURLConnection httpConnection=(HttpURLConnection)url.openConnection();
httpConnection.setRequestProperty("User-Agent", "NextFox");
String sProperty="bytes= "+nStartPos+"-";
httpConnection.setRequestProperty("RANGE", sProperty);
Utility.log(sProperty);
InputStream input=httpConnection.getInputStream(); //創建輸入流對象
byte[] b=new byte[1024];
int nRead;
while((nRead=input.read(b,0,1024))>0 && nStartPos<nEndPos && !bStop){
nStartPos+=fileAccess.write(b,0,nRead);
}
Utility.log("Thread "+nThreadID + "is over!");
bDownOver=true;
}
catch(Exception e){
e.printStackTrace();
}
}
}
public void logResponseHead(HttpURLConnection con){ //處理和響應服務器頭數據
for(int i=1;;i++){
String header=con.getHeaderFieldKey(i);
if(header!=null)
Utility.log(header+" : "+con.getHeaderField(header));
else
break;
}
}
public void splitterStop(){
bStop=true;
}
}
import java.io.*;
import java.net.*;
public class FileSplitterFetch extends Thread {
String sURL; //定義文件傳輸時使用的變量
long nStartPos; //分段文件傳輸開始位置
long nEndPos; //分段文件傳輸結束位置
int nThreadID; //子線程ID
boolean bDownOver=false; //完成文件傳輸
boolean bStop=false; //停止文件傳輸
FileAccess fileAccess=null;
public FileSplitterFetch(String sURL,String sName,long nStart,long nEnd,int id) throws IOException{
this.sURL=sURL;
this.nStartPos=nStart;
this.nEndPos=nEnd;
nThreadID=id;
fileAccess=new FileAccess(sName,nStartPos); //創建文件并打開
}
public void run(){
while(nStartPos<nEndPos && !bStop){
try{ //創建連接
URL url=new URL(sURL);
HttpURLConnection httpConnection=(HttpURLConnection)url.openConnection();
httpConnection.setRequestProperty("User-Agent", "NextFox");
String sProperty="bytes= "+nStartPos+"-";
httpConnection.setRequestProperty("RANGE", sProperty);
Utility.log(sProperty);
InputStream input=httpConnection.getInputStream(); //創建輸入流對象
byte[] b=new byte[1024];
int nRead;
while((nRead=input.read(b,0,1024))>0 && nStartPos<nEndPos && !bStop){
nStartPos+=fileAccess.write(b,0,nRead);
}
Utility.log("Thread "+nThreadID + "is over!");
bDownOver=true;
}
catch(Exception e){
e.printStackTrace();
}
}
}
public void logResponseHead(HttpURLConnection con){ //處理和響應服務器頭數據
for(int i=1;;i++){
String header=con.getHeaderFieldKey(i);
if(header!=null)
Utility.log(header+" : "+con.getHeaderField(header));
else
break;
}
}
public void splitterStop(){
bStop=true;
}
}創建設置和獲取網絡信息類,類名為SiteInfoBean.java view plaincopy to clipboardprint?
public class SiteInfoBean { //定義獲取和設置相關文件類信息
private String sSiteURL; //定義URL變量
private String sFilePath; //定義存文件路徑變量
private String sFileName; //定義文件名變量
private int nSplitter; //定義傳輸文件計數器
public SiteInfoBean(){
this("","","",5);
}
public SiteInfoBean(String sURL,String sPath,String sName,int nSplitter){
sSiteURL=sURL;
sFilePath=sPath;
sFileName=sName;
this.nSplitter=nSplitter;
}
public String getSSiteURL(){
return sSiteURL;
}
public void setSSiteURL(String value){
sSiteURL=value;
}
public String getSFilePath(){
return sFilePath;
}
public void setSFilePath(String value){
sFilePath=value;
}
public String getSFileName(){
return sFileName;
}
public void setSFileName(String value){
sFileName=value;
}
public int getNSplitter(){
return nSplitter;
}
public void setNSplitter(int nCount){
nSplitter=nCount;
}
}
public class SiteInfoBean { //定義獲取和設置相關文件類信息
private String sSiteURL; //定義URL變量
private String sFilePath; //定義存文件路徑變量
private String sFileName; //定義文件名變量
private int nSplitter; //定義傳輸文件計數器
public SiteInfoBean(){
this("","","",5);
}
public SiteInfoBean(String sURL,String sPath,String sName,int nSplitter){
sSiteURL=sURL;
sFilePath=sPath;
sFileName=sName;
this.nSplitter=nSplitter;
}
public String getSSiteURL(){
return sSiteURL;
}
public void setSSiteURL(String value){
sSiteURL=value;
}
public String getSFilePath(){
return sFilePath;
}
public void setSFilePath(String value){
sFilePath=value;
}
public String getSFileName(){
return sFileName;
}
public void setSFileName(String value){
sFileName=value;
}
public int getNSplitter(){
return nSplitter;
}
public void setNSplitter(int nCount){
nSplitter=nCount;
}
}創建保存獲取的網絡文件類,類名為FileAccess.java view plaincopy to clipboardprint?
import java.io.*;
public class FileAccess implements Serializable { //定義文件訪問類
RandomAccessFile oSavedFile;
long nPos;
public FileAccess() throws IOException{
this("",0);
}
public FileAccess(String sName,long nPos) throws IOException{
oSavedFile=new RandomAccessFile(sName,"rw");
this.nPos=nPos;
oSavedFile.seek(nPos);
}
public synchronized int write(byte[] b,int nStart,int nLen){
int n=-1;
try{
oSavedFile.write(b,nStart,nLen);
n=nLen;
}
catch(IOException e){
e.printStackTrace();
}
return n;
}
}
import java.io.*;
public class FileAccess implements Serializable { //定義文件訪問類
RandomAccessFile oSavedFile;
long nPos;
public FileAccess() throws IOException{
this("",0);
}
public FileAccess(String sName,long nPos) throws IOException{
oSavedFile=new RandomAccessFile(sName,"rw");
this.nPos=nPos;
oSavedFile.seek(nPos);
}
public synchronized int write(byte[] b,int nStart,int nLen){
int n=-1;
try{
oSavedFile.write(b,nStart,nLen);
n=nLen;
}
catch(IOException e){
e.printStackTrace();
}
return n;
}
}創建在下載過程中應用的工具類,名為Utility.java view plaincopy to clipboardprint?
public class Utility { //定義輸出提示信息及線程sleep類
public Utility(){
}
public static void sleep(int nSecond){
try{
Thread.sleep(nSecond);
}
catch(Exception e){
e.printStackTrace();
}
}
public static void log(String sMsg){
System.out.println(sMsg);
}
public static void log(int sMsg){
System.out.println(sMsg);
}
}
public class Utility { //定義輸出提示信息及線程sleep類
public Utility(){
}
public static void sleep(int nSecond){
try{
Thread.sleep(nSecond);
}
catch(Exception e){
e.printStackTrace();
}
}
public static void log(String sMsg){
System.out.println(sMsg);
}
public static void log(int sMsg){
System.out.println(sMsg);
}
}
創建包含main()方法的測試類,文件名為TestMethod.java view plaincopy to clipboardprint?
public class TestMethod {
private String sWebAddr="http://localhost:8080/java.zip"; //定義WEB地址和文件名
private String sSavePath="d:\\temp"; //定義存文件路徑
private String sSaveName="java.zip"; //定義文件名
public TestMethod(){
try{
SiteInfoBean bean=new SiteInfoBean(sWebAddr,sSavePath,sSaveName,5);
SiteFileFetch fileFetch=new SiteFileFetch(bean);
fileFetch.start();
}
catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args){
new TestMethod();
}
}
public class TestMethod {
private String sWebAddr="http://localhost:8080/java.zip"; //定義WEB地址和文件名
private String sSavePath="d:\\temp"; //定義存文件路徑
private String sSaveName="java.zip"; //定義文件名
public TestMethod(){
try{
SiteInfoBean bean=new SiteInfoBean(sWebAddr,sSavePath,sSaveName,5);
SiteFileFetch fileFetch=new SiteFileFetch(bean);
fileFetch.start();
}
catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args){
new TestMethod();
}
}以上六個類的功能為: SiteFileFetch類負責下載整個文件以及控制FileSplitterFetch類的線程 FileSplitterFetch類負責下載部分(一塊)文件 SiteInfoBean類提供下載整個文件所需要的信息,例如文件保存目錄,文件名和下載文件的URL等信息 FileAccess類負責文件的存儲 Utility為工具類,提供下載文件時所使用的方法 TestMethod類為測試類,執行該實例程序入口 在下載文件過程中,主要應用方法有: (1)完成與服務器連接 view plaincopy to clipboardprint?
URL url=new URL("下載文件url地址和文件名");
HttpURLConnection httpConnection=(HttpURLConnection)url.openConnection();
URL url=new URL("下載文件url地址和文件名");
HttpURLConnection httpConnection=(HttpURLConnection)url.openConnection();(2)設置與服務器連接屬性,即請求連接服務器信息 view plaincopy to clipboardprint?
httpConnection.setRequestProperty("User-Agent","NetFox");
httpConnection.setRequestProperty("User-Agent","NetFox");(3)設置下載文件的開始位置 view plaincopy to clipboardprint?
httpConnection.setRequestProperty("RANGE","bytes=0");
httpConnection.setRequestProperty("RANGE","bytes=0");(4)創建輸入流,以輸入流形式下載文件 view plaincopy to clipboardprint?
InputStream input=httpConnection.getInputStream();
InputStream input=httpConnection.getInputStream();(5)創建隨機訪問文件對象 view plaincopy to clipboardprint?
RandomAccess oSavedFile=new RandomAccessFile("java.zip","rw");
RandomAccess oSavedFile=new RandomAccessFile("java.zip","rw");(6)設置保存文件指針 view plaincopy to clipboardprint?
oSavedFile.seek(nPos);
oSavedFile.seek(nPos);(7)保存文件 view plaincopy to clipboardprint?
byte[] b=new byte[1024];
int nRead;
while((nRead=input.read(b,0,1024))>0){
oSavedFile.write(b,0,nRead);
}
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/kuyesuifeng/archive/2008/06/27/2591972.aspx