由於業務需要,手機需要采用http方式傳輸文件到后台WEB服務器,1、2百K的小文件不會有太大問題,幾M甚至幾百M的文件就很容易傳輸失敗。所以考慮實現HTTP文件斷點續傳功能,基本流程如下:
1.客戶端計算本地要上傳的文件的hashcode
2.根據指定的塊大小和文件大小計算最終的塊數
3.發送文件信息到服務器包括要上傳的文件名、大小、類型、塊數、Hashcode
4.服務器根據hashcode查詢服務器上是否已經存在對應的文件,以及文件的上傳狀態(上傳是否完成、是否組裝完成、已經上傳了哪些塊)
5.6.已經上傳完成的讀取文件URL地址返回給客戶端
7.8.未上傳完成的返回已經上傳的塊編號
9.客戶端根據返回值判斷,如果未上傳完成則從本地文件中讀取未上傳完成的塊內容
10.使用HTTP方式上傳到服務器
11.記錄已經上傳完成的塊到數據庫
12.檢查整個文件是否已經上傳完成
13.未完成則返回已經上傳的塊編號到客戶端讓它繼續上傳
14.上傳完成則進行塊文件合並過程,將其合並成目標文件
15.合並完成后返回目標文件的URL地址
首先是數據庫表格:
fseq int primary key auto_increment, #自增序列
fusername varchar( 50), #上傳者
fhashcode varchar( 100), #hash碼
fsize int, #文件大小
fblocks int, #塊數
ftype varchar( 50), #文件類型
fready varchar( 1024), #已上傳完成的塊編號
finerpath varchar( 200), #內部存儲路徑
fouterpath varchar( 200), #外部存儲路徑
fisfinished int default 0, #要否上傳完成
ftime datetime #創建時間
)
接下來是客戶端代碼:
public class Auth{
public static byte[] create(String filename) throws Excepiton{
InputStream fis = new FileInputStream(filename);
byte[] buf= new byte[1024];
MessageDigest com=MessageDigest.getInstance("MD5");
int num;
do{
num=fis.read(buf);
if(num>0){
com.update(buf,0,num);
}
} while(num!=-1)
fis.close();
return com.digest();
}
public static String getMD5(String filename) throw Exception {
byte[] b =create(filename);
String result="";
for( int i=0;i<b.length;i++){
result+=Integer.toString( (b[i]&0xff)+0x100,16).substring(1);
}
return result;
}
}
服務器端代碼包括以下幾部分:
1.新增要上傳的文件信息。
2.接收文件的各個塊。
3.合並塊。
1:
public void saveFileInfo(){
//先從數據庫中根據hashcode查找
FileInfo info= fileSer.getFileByHash(hashcode);
if(info==null){}
//找不到則新增文件信息
fileSer.saveFileInfo(username,filename,filesize,hashcode,blocks,filetype);
return "added";
}
if(info.fisfinished){
//如果已經上傳完畢則返回外部訪問路徑
return info.fouterpath;
}
else{
//未上傳完畢則返回已經上傳的塊
return info.fready;
}
)
2:
publicvoid saveblock(){
if([這里驗證與塊一起上傳的block信息]){
return "error";
}
if(info!=null){
//如果已經上傳完畢則返回外部訪問路徑
return info.fouterpath;
FileOutputStream outStream = new FileOutputStream(block存儲路徑+hashcode+block編號);
int len=-1;
byte[]buff= new byte[1024];
while((len=inStream.read(buff))!=-1){
outStream.write(buff,0,len);
}
outStream.flush();
outStream.close();
//更新數據庫中已經上傳的blocks信息
fileSer.updateBlocks(hashcode,num);
//進行合並檢查
return union();
}
}
3:
int num =info.getFblocks();
if(info.fisfinished){
return info.fouterpah();
}
//這里要檢查下上傳的塊數量是否與num一致
try{
FileOutputStream outStream = new FileOutputStream(文件存儲路徑+info.ffilename);
File inputfile=null;
for(int i=1;i<num;i++){
inputfile = new File(block存儲路徑+info.fhashcode+i);
FileInputStream inStream = new FileInputStream(inputfile);
int len=-1;
byte[]buff = new byte[1024];
while((len=inStream.read(buff))!=-1){
outStream.write(buff,0,len);
}
outStream.flush();
inStream.close();
inputfile.delete();
}
outStream.close();
}catch(Excption ex){
return info.fblocks();
}
fileSer.updateouterpath(文件存儲路徑+info.ffilename,info.fhashcode);
fileSer.updateFisfinished(true,info.fhashcode);
return 文件存儲路徑+info.ffilename;
}