由于要用APPLET實現大文件FTP上傳下載,從網上搜索了幾下,找到很多資料,最后決定采用基于 org.apache.commons.net.ftp包實現FTP上傳下載,Net包中的類既提供對協議的底層訪問也有高層的抽象。在大多數情況下,抽 象是足夠的,它可以使你不必編寫解析各種協議的底層套接字的代碼。使用抽象不會損失任何功能。
??? 借此感嘆,org.apache.commons開源包真是森羅萬象,應有盡有。反觀國內打著開源旗號的軟件也不少,但沒幾個能在當前軟林揚名立萬的,借山本趙一句經典臺詞:悲哀 悲哀 真是悲哀。
??? 開發環境:winxp+eclipse3.2.2+struts2.0+jse5.0
??? 最早采用以下代碼:
package yp;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
?
public class ContinueFTP{???
?? private File file=null;
?? //是否完整保留原文件名
?? private boolean isSaveFileName = true;
?? //枚舉上傳狀態
?? public enum UploadStatus {?
???????? Create_Directory_Fail,????? //遠程服務器相應目錄創建失敗?
???????? Create_Directory_Success,?? //遠程服務器創建目錄成功?
???????? Upload_New_File_Success,??? //上傳新文件成功?
???????? Upload_New_File_Failed,???? //上傳新文件失敗?
???????? File_Exits,???????????????? //文件已經存在?
???????? Remote_Bigger_Local,??????? //遠程文件大于本地文件?
???????? Upload_From_Break_Success,? //斷點續傳成功?
???????? Upload_From_Break_Failed,?? //斷點續傳失敗?
???????? Delete_Remote_Faild;??????? //刪除遠程文件失敗?
??? }
???
??? //枚舉下載狀態
??? public enum DownloadStatus {?
????????? Remote_File_Noexist,??? //遠程文件不存在?
????????? Local_Bigger_Remote,??? //本地文件大于遠程文件?
????????? Download_From_Break_Success,??? //斷點下載文件成功?
????????? Download_From_Break_Failed,???? //斷點下載文件失敗?
????????? Download_New_Success,?????????? //全新下載文件成功?
????????? Download_New_Failed;??????????? //全新下載文件失敗?
??? }
???
??? public void init(){
????
??? }
???
??? public FTPClient ftpClient = new FTPClient();?
????????
???? public ContinueFTP(){?
?????????? //設置將過程中使用到的命令輸出到控制臺?
?????????? this.ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));?
???? }?
??????
???
??? public String getRemoteFileName(String localFileName){
???? String fileName ="";
???? //分隔符
???? String sepaRator="\";
??????? if (localFileName.indexOf(sepaRator)<0)
???????? sepaRator="/";
??????? //最后分隔符位置
??????? int idx = localFileName.lastIndexOf(sepaRator)+1;
??????? fileName = localFileName.substring(idx);
??????? return fileName;
??? }????
?????
??????
?????? public boolean isFileExist(String remoteFileName) throws IOException{
??????? boolean isFileExist = false;??????????
?????????? //檢查遠程是否存在文件?
?????????? FTPFile[] files = ftpClient.listFiles(new String(remoteFileName.getBytes("GBK"),"iso-8859-1"));?
?????????? if(files!=null && files.length >= 1){?
????????????? isFileExist = true;
??????? }
??????? return isFileExist;
?????? }
??????
??????
?????? ?
?????? public boolean connect(String hostname,int port,String username,String password) throws Exception{?
??????? boolean bl = false;
??????? try{
???????? ftpClient.connect(hostname, port);?
??????? }catch(Exception e){
????????? //可具體報錯到主機和端口號
????? throw new BaseException("FTPConnError01",new String[]{"connect",e.getMessage()});
??????? }
??????? try{
???????? //ftpClient.setControlEncoding("GBK");
??????????? if(FTPReply.isPositiveCompletion(ftpClient.getReplyCode())){?
??????????????? if(ftpClient.login(username, password)){?
???????????????? bl = true;?
??????????????? }?
??????????? }
??????? }catch(Exception e){
????????? //可具體報錯到用戶和密碼
????? throw new BaseException("FTPConnError02",new String[]{"connect",e.getMessage()});
??????? }
?????????? return bl;?
?????? }?
????????
?????? ?
?????? public DownloadStatus download(String remote,String local) throws Exception{?
?????????? //設置被動模式?
?????????? ftpClient.enterLocalPassiveMode();?
?????????? //設置以二進制方式傳輸?
?????????? ftpClient.setFileType(FTP.BINARY_FILE_TYPE);?
?????????? DownloadStatus result;?
????????????
?????????? //檢查遠程文件是否存在?
?????????? FTPFile[] files = ftpClient.listFiles(new String(remote.getBytes("GBK"),"iso-8859-1"));?
?????????? if(files.length != 1){?
??????????? throw new BaseException("CellDataInputService",new String[]{"download","遠程文件"+remote+"不存在"});
?????????? }?
????????????
?????????? long lRemoteSize = files[0].getSize();?
?????????? File f = new File(local);?
?????????? //本地存在文件,進行斷點下載?
?????????? if(f.exists()){?
?????????????? long localSize = f.length();?
?????????????? //判斷本地文件大小是否大于遠程文件大小?
?????????????? if(localSize >= lRemoteSize){?
?????????????????? System.out.println("本地文件大于遠程文件,下載中止");?
?????????????????? return DownloadStatus.Local_Bigger_Remote;?
?????????????? }?
????????????????
?????????????? //進行斷點續傳,并記錄狀態?
?????????????? FileOutputStream out = new FileOutputStream(f,true);?
?????????????? ftpClient.setRestartOffset(localSize);?
?????????????? InputStream in = ftpClient.retrieveFileStream(new String(remote.getBytes("GBK"),"iso-8859-1"));?
?????????????? byte[] bytes = new byte[1024];?
?????????????? long step = lRemoteSize /100;?
?????????????? long process=localSize /step;?
?????????????? int c;?
?????????????? while((c = in.read(bytes))!= -1){?
?????????????????? out.write(bytes,0,c);?
?????????????????? localSize+=c;?
?????????????????? long nowProcess = localSize /step;?
?????????????????? if(nowProcess > process){?
?????????????????????? process = nowProcess;?
?????????????????????? if(process % 10 == 0)?
?????????????????????????? System.out.println("下載進度:"+process);?
?????????????????????? //TODO 更新文件下載進度,值存放在process變量中?
?????????????????? }?
?????????????? }?
?????????????? in.close();?
?????????????? out.close();?
?????????????? boolean isDo = ftpClient.completePendingCommand();?
?????????????? if(isDo){?
?????????????????? result = DownloadStatus.Download_From_Break_Success;?
?????????????? }else {?
?????????????????? result = DownloadStatus.Download_From_Break_Failed;?
?????????????? }?
?????????? }else {?
?????????????? OutputStream out = new FileOutputStream(f);?
?????????????? InputStream in= ftpClient.retrieveFileStream(new String(remote.getBytes("GBK"),"iso-8859-1"));?
?????????????? byte[] bytes = new byte[1024];?
?????????????? long step = lRemoteSize /100;?
?????????????? long process=0;?
?????????????? long localSize = 0L;?
?????????????? int c;?
?????????????? while((c = in.read(bytes))!= -1){?
?????????????????? out.write(bytes, 0, c);?
?????????????????? localSize+=c;?
?????????????????? long nowProcess = localSize /step;?
?????????????????? if(nowProcess > process){?
?????????????????????? process = nowProcess;?
?????????????????????? if(process % 10 == 0)?
?????????????????????????? System.out.println("下載進度:"+process);?
?????????????????????? //TODO 更新文件下載進度,值存放在process變量中?
?????????????????? }?
?????????????? }?
?????????????? in.close();?
?????????????? out.close();?
?????????????? boolean upNewStatus = ftpClient.completePendingCommand();?
?????????????? if(upNewStatus){?
?????????????????? result = DownloadStatus.Download_New_Success;?
?????????????? }else {?
?????????????????? result = DownloadStatus.Download_New_Failed;?
?????????????? }?
?????????? }?
?????????? return result;?
?????? }? ? ? ??
?????? public UploadStatus upload(File localFile,String remote) throws IOException{?
?????????? //設置PassiveMode傳輸?
?????????? ftpClient.enterLocalPassiveMode();?
?????????? //設置以二進制流的方式傳輸?
?????????? ftpClient.setFileType(FTP.BINARY_FILE_TYPE);?
?????????? //ftpClient.setControlEncoding("GBK");?
?????????? UploadStatus result;?
?????????? //對遠程目錄的處理?
?????????? String remoteFileName = remote;?
?????????? if(remote.contains("/")){?
?????????????? remoteFileName = remote.substring(remote.lastIndexOf("/")+1);?
?????????????? //創建服務器遠程目錄結構,創建失敗直接返回?
?????????????? if(CreateDirecroty(remote, ftpClient)==UploadStatus.Create_Directory_Fail){?
?????????????????? return UploadStatus.Create_Directory_Fail;?
?????????????? }?
?????????? }?
????????????
?????????? //檢查遠程是否存在文件?
?????????? FTPFile[] files = ftpClient.listFiles(new String(remoteFileName.getBytes("GBK"),"iso-8859-1"));?
?????????? if(files!=null && files.length == 1){?
?????????????? long remoteSize = files[0].getSize();?
?????????????? //File f = new File(local);?
?????????????? long localSize = localFile.length();?
?????????????? if(remoteSize==localSize){?
?????????????????? return UploadStatus.File_Exits;?
?????????????? }else if(remoteSize > localSize){?
?????????????????? return UploadStatus.Remote_Bigger_Local;?
?????????????? }?
????????????????
?????????????? //嘗試移動文件內讀取指針,實現斷點續傳?
?????????????? result = uploadFile(remoteFileName, localFile, ftpClient, remoteSize);?
????????????????
?????????????? //如果斷點續傳沒有成功,則刪除服務器上文件,重新上傳?
?????????????? if(result == UploadStatus.Upload_From_Break_Failed){?
?????????????????? if(!ftpClient.deleteFile(remoteFileName)){?
?????????????????????? return UploadStatus.Delete_Remote_Faild;?
?????????????????? }?
?????????????????? result = uploadFile(remoteFileName, localFile, ftpClient, 0);?
?????????????? }?
?????????? }else {?
?????????????? result = uploadFile(remoteFileName, localFile, ftpClient, 0);?
?????????? }?
?????????? return result;?
?????? }?
?????? ?
?????? public void disconnect() throws IOException{?
?????????? if(this.ftpClient.isConnected()){?
??????????? this.ftpClient.disconnect();?
?????????? }?
?????? }?
????????
??????
?????? public String CreateDirecroty(String remoteDir)throws IOException{
??????? String fillDir = "";
????????????? UploadStatus st = CreateDirecroty(remoteDir,this.ftpClient);
????????????? if (st == UploadStatus.Create_Directory_Success)
????????? fillDir = remoteDir;
??????? else
??????? fillDir = "";
?????????????
??????? return fillDir;
?????? }
??????
?????? ?
?????? public UploadStatus CreateDirecroty(String remote,FTPClient ftpClient) throws IOException{?
?????????? UploadStatus status = UploadStatus.Create_Directory_Success;?
?????????? String directory = remote.substring(0,remote.lastIndexOf("/")+1);?
?????????? if(!directory.equalsIgnoreCase("/")&&!ftpClient.changeWorkingDirectory(new String(directory.getBytes("GBK"),"iso-8859-1"))){?
?????????????? //如果遠程目錄不存在,則遞歸創建遠程服務器目錄?
?????????????? int start=0;?
?????????????? int end = 0;?
?????????????? if(directory.startsWith("/")){?
?????????????????? start = 1;?
?????????????? }else{?
?????????????????? start = 0;?
?????????????? }?
?????????????? end = directory.indexOf("/",start);?
?????????????? while(true){?
?????????????????? String subDirectory = new String(remote.substring(start,end).getBytes("GBK"),"iso-8859-1");?
?????????????????? if(!ftpClient.changeWorkingDirectory(subDirectory)){?
?????????????????????? if(ftpClient.makeDirectory(subDirectory)){?
?????????????????????????? ftpClient.changeWorkingDirectory(subDirectory);?
?????????????????????? }else {?
?????????????????????????? System.out.println("創建目錄失敗");?
?????????????????????????? return UploadStatus.Create_Directory_Fail;?
?????????????????????? }?
?????????????????? }?
????????????????????
?????????????????? start = end + 1;?
?????????????????? end = directory.indexOf("/",start);?
????????????????????
?????????????????? //檢查所有目錄是否創建完畢?
?????????????????? if(end <= start){?
?????????????????????? break;?
?????????????????? }?
?????????????? }?
?????????? }?
?????????? return status;?
?????? }?
????????
?????? ?
?????? public UploadStatus uploadFile(String remoteFile,File localFile,FTPClient ftpClient,long remoteSize) throws IOException{?
?????????? UploadStatus status;?
?????????? //顯示進度的上傳?
?????????? long step = localFile.length() / 100;?
?????????? long process = 0;?
?????????? long localreadbytes = 0L;?
?????????? RandomAccessFile raf = new RandomAccessFile(localFile,"r");?
?????????? OutputStream out = ftpClient.appendFileStream(new String(remoteFile.getBytes("GBK"),"iso-8859-1"));?
?????????? //斷點續傳?
?????????? if(remoteSize>0){?
?????????????? ftpClient.setRestartOffset(remoteSize);?
?????????????? process = remoteSize /step;?
?????????????? raf.seek(remoteSize);?
?????????????? localreadbytes = remoteSize;?
?????????? }?
?????????? byte[] bytes = new byte[1024];?
?????????? int c;?
?????????? while((c = raf.read(bytes))!= -1){?
?????????????? out.write(bytes,0,c);?
?????????????? localreadbytes+=c;?
????????????????? //TODO 匯報上傳狀態?
?????????????? if(localreadbytes / step != process){?
?????????????????? process = localreadbytes / step;?
?????????????????? System.out.println("上傳進度:" + process);?
?????????????? }?
?????????? }?
?????????? out.flush();?
?????????? raf.close();?
?????????? out.close();?
?????????? boolean result =ftpClient.completePendingCommand();?
?????????? if(remoteSize > 0){?
?????????????? status = result?UploadStatus.Upload_From_Break_Success:UploadStatus.Upload_From_Break_Failed;?
?????????? }else {?
?????????????? status = result?UploadStatus.Upload_New_File_Success:UploadStatus.Upload_New_File_Failed;?
?????????? }?
?????????? return status;?
?????? }?
??????
?????? public List<String> getRemoteFileList(String remoteDir){
???????? List<String> list = new ArrayList<String>();
????????????? FTPFile[] files;
???? try {
????? files = ftpClient.listFiles(remoteDir);
?????????????? for (int i = 0; i < files.length; i++) {
??????????????? list.add(files[i].getName());
?????????????? }
???? } catch (IOException e) {
????? // TODO Auto-generated catch block
????? e.printStackTrace();
???? }
????????????? return list;
??????? }
??????
??????
?????? public boolean deleteFile(String fillFileName) throws Exception {
??????? boolean bl = false;
??????? this.ftpClient.deleteFile(fillFileName);
?????????? int status = this.ftpClient.getReplyCode();
?????????? if(status == 250){
??????????? bl = true;
??????????? System.out.println("成功刪除FTP服務器中文件:" + fillFileName);???????????
?????????? }
?????????? return bl;
?????? }
?
? ? ? ? ?public boolean deleteDir(String remoteDir)throws Exception {
??????? boolean isDel = false;
??????? this.ftpClient.removeDirectory(remoteDir);
?????????? int status = this.ftpClient.getReplyCode();
?????????? if(status == 250){
??????????? isDel = true;
??????????? System.out.println("成功刪除FTP服務器中目錄:" + remoteDir);???????????
?????????? }
??????? return isDel;
?????? }
????????
?????? public static void main(String[] args) throws Exception {
??????? ContinueFTP myFtp = new ContinueFTP();?
??????? try {?
??????????? long l1 = System.currentTimeMillis();
??????????? System.out.println("begin:"+ l1);
?????????????? if (myFtp.connect("10.68.7.182", 21, "a", "a")) {
??????????????? String mkDir = myFtp.CreateDirecroty("TTT/ccc/");
??????????????? if (mkDir != null && !mkDir.trim().equals(""))
???????????????? System.out.println("mkDir success:"+mkDir);
??????????????? //myFtp.download( "/XA01B03H05/5.mp3",file,"0");
??????????????? //myFtp.upload("/XA01B03H05/5.mp3", "/云臺山.mpg");
??????????????? //myFtp.delete_file("/tmp.txt");
??????????????? //String str = new String("電視劇");
??????????????? //myFtp.ftpClient.removeDirectory("/kkk/jk/");
??????????????? //myFtp.ftpClient.makeDirectory(new String(str.getBytes("GBK"),"iso-8859-1"));
??????????????? myFtp.disconnect();
???????????? long l2 = System.currentTimeMillis();
???????????? System.out.println("end:"+ l2);
??????????????? System.out.println("remaining:"+(l2-l1));
?????????????? }
?????????? } catch (IOException e) {?
?????????????? System.out.println("連接FTP出錯:"+e.getMessage());?
?????????? }
?????????
?????? }
?? public File getFile() {
??? return file;
?? }
?? public void setFile(File file) {
??? this.file = file;
?? }
?? public boolean isSaveFileName() {
??? return isSaveFileName;
?? }
?? public void setSaveFileName(boolean isSaveFileName) {
??? this.isSaveFileName = isSaveFileName;
?? }
??
??
}
?
??? 通過main函數測試效果也不錯,還顯示上傳或下載進度,再寫一個對應action及jsp實現ftp上傳下載,不過我吃過一次大虧,本來web服務器是本機,我原來做的上傳下載都沒有問題,但web服務器不在本機,就報說找不到文件!
??? 后來終于想明白了,系統還是web服務器上路徑找文件,當然找不到。
??? 難道通過瀏覽器訪問本地資源就真的無解了嗎?
??? 當然不是,也在找了很多解決方案,各有所長,又各有短處.
1.使用表單直接提交
? 這個方案肯定是被弊掉的,人一多就可能拖跨服務器.
2.使用FLASH進行文件上傳
? 這個方案也嘗試過,不過據說AS3只支持100M左右的文件上傳,大文件無法上傳,不知道是不是這樣?如果是這樣的話,那么這個方案也將行不通了.使用FLASH進行文件上傳相對而言開發不會太困難.
3.使用APPLET進行文件上傳
? 使用APPLET開發文件上傳控件,這個對于使用JAVA來進行開發的非常方便,因為我們項目就是使用JAVA的,不過APPLET有安全策略的問題,無 法讀取客戶端的問題.如果要,那么用戶必須修改其java.policy文件,這對于用戶來講簡直是不可能的.如果使用程序下載動態修改也會比較麻煩.其 實還有一個破解之法,就是采用數字證書。
? 缺點:1)、客戶端必須安裝JRE;2)、想辦法突破APPLET有安全策略的問題
? 優點:java編寫,支持多瀏覽器
4.使用ACTIVEX進行文件上傳
? 這是我目前認為比較可行的方式,而且網上也有很多類似這樣的控件,但是都不是免費的,所以只能自己想辦法解決了.使用ACTIVEX開發,可以使用C++、DELPHI等來進行開發
? 缺點:1>客戶端推薦IE;2>IE安全設置中啟用activex控件
? 優點:ACTIVEX開發速度快、界面友好
? 以下方案先采用第三種方案---Java applet,當年讓Java 大火了一把的號稱與微軟的ActiveX 相提并論的技術當然,現在Java 出了JavaFX,是不是Applet 的替代品呢?你猜,猜不著呀?你再猜^_^