java實現FTP多線程斷點續傳,上傳下載!

添加 apache.commons.NET.ftp 包

[java] view plain copy
  1. package com.ftp;   
  2.   
  3. import java.io.File;     
  4. import java.io.FileOutputStream;     
  5. import java.io.IOException;     
  6. import java.io.InputStream;     
  7. import java.io.OutputStream;     
  8. import java.io.PrintWriter;     
  9. import java.io.RandomAccessFile;     
  10.     
  11.     
  12. import org.apache.commons.net.PrintCommandListener;     
  13. import org.apache.commons.net.ftp.FTP;     
  14. import org.apache.commons.net.ftp.FTPClient;     
  15. import org.apache.commons.net.ftp.FTPFile;     
  16. import org.apache.commons.net.ftp.FTPReply;     
  17. import org.junit.Test;   
  18. /** *//**   
  19. * 支持斷點續傳的FTP實用類   
  20. * @version 0.1 實現基本斷點上傳下載   
  21. * @version 0.2 實現上傳下載進度彙報   
  22. * @version 0.3 實現中文目錄創建及中文文件創建,添加對於中文的支持   
  23. */    
  24. public class ContinueFTP2  implements Runnable{     
  25.   
  26. //枚舉類UploadStatus代碼   
  27.   
  28. public enum UploadStatus {   
  29. Create_Directory_Fail,   //遠程服務器相應目錄創建失敗   
  30. Create_Directory_Success, //遠程服務器闖將目錄成功   
  31. Upload_New_File_Success, //上傳新文件成功   
  32. Upload_New_File_Failed,   //上傳新文件失敗   
  33. File_Exits,      //文件已經存在   
  34. Remote_Bigger_Local,   //遠程文件大於本地文件   
  35. Upload_From_Break_Success, //斷點續傳成功   
  36. Upload_From_Break_Failed, //斷點續傳失敗   
  37. Delete_Remote_Faild;   //刪除遠程文件失敗   
  38. }   
  39.   
  40. //枚舉類DownloadStatus代碼   
  41. public enum DownloadStatus {   
  42. Remote_File_Noexist, //遠程文件不存在   
  43. Local_Bigger_Remote, //本地文件大於遠程文件   
  44. Download_From_Break_Success, //斷點下載文件成功   
  45. Download_From_Break_Failed,   //斷點下載文件失敗   
  46. Download_New_Success,    //全新下載文件成功   
  47. Download_New_Failed;    //全新下載文件失敗   
  48. }   
  49.   
  50.     public FTPClient ftpClient = new FTPClient();     
  51.     private String ftpURL,username,pwd,ftpport,file1,file2;      
  52.     public ContinueFTP2(String _ftpURL,String _username,String _pwd,String _ftpport,String _file1,String _file2 ){     
  53.         //設置將過程中使用到的命令輸出到控制檯     
  54.      ftpURL = _ftpURL;   
  55.      username = _username;   
  56.      pwd = _pwd;   
  57.      ftpport = _ftpport;   
  58.      file1 = _file1;   
  59.      file2 = _file2;   
  60.         this.ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));     
  61.     }     
  62.          
  63.     /** *//**   
  64.      * 連接到FTP服務器   
  65.      * @param hostname 主機名   
  66.      * @param port 端口   
  67.      * @param username 用戶名   
  68.      * @param password 密碼   
  69.      * @return 是否連接成功   
  70.      * @throws IOException   
  71.      */    
  72.     public boolean connect(String hostname,int port,String username,String password) throws IOException{     
  73.         ftpClient.connect(hostname, port);     
  74.         ftpClient.setControlEncoding("GBK");     
  75.         if(FTPReply.isPositiveCompletion(ftpClient.getReplyCode())){     
  76.             if(ftpClient.login(username, password)){     
  77.                 return true;     
  78.             }     
  79.         }     
  80.         disconnect();     
  81.         return false;     
  82.     }     
  83.          
  84.     /** *//**   
  85.      * 從FTP服務器上下載文件,支持斷點續傳,上傳百分比彙報   
  86.      * @param remote 遠程文件路徑   
  87.      * @param local 本地文件路徑   
  88.      * @return 上傳的狀態   
  89.      * @throws IOException   
  90.      */    
  91.     public DownloadStatus download(String remote,String local) throws IOException{     
  92.         //設置被動模式     
  93.         ftpClient.enterLocalPassiveMode();     
  94.         //設置以二進制方式傳輸     
  95.         ftpClient.setFileType(FTP.BINARY_FILE_TYPE);     
  96.         DownloadStatus result;     
  97.              
  98.         //檢查遠程文件是否存在     
  99.         FTPFile[] files = ftpClient.listFiles(new String(remote.getBytes("GBK"),"iso-8859-1"));     
  100.         if(files.length != 1){     
  101.             System.out.println("遠程文件不存在");     
  102.             return DownloadStatus.Remote_File_Noexist;     
  103.         }     
  104.              
  105.         long lRemoteSize = files[0].getSize();     
  106.         File f = new File(local);     
  107.         //本地存在文件,進行斷點下載     
  108.         if(f.exists()){     
  109.             long localSize = f.length();     
  110.             //判斷本地文件大小是否大於遠程文件大小     
  111.             if(localSize >= lRemoteSize){     
  112.                 System.out.println("本地文件大於遠程文件,下載中止");     
  113.                 return DownloadStatus.Local_Bigger_Remote;     
  114.             }     
  115.                  
  116.             //進行斷點續傳,並記錄狀態     
  117.             FileOutputStream out = new FileOutputStream(f,true);     
  118.             ftpClient.setRestartOffset(localSize);     
  119.             InputStream in = ftpClient.retrieveFileStream(new String(remote.getBytes("GBK"),"iso-8859-1"));     
  120.             byte[] bytes = new byte[1024];     
  121.             long step = lRemoteSize /100;     
  122.             long process=localSize /step;     
  123.             int c;     
  124.             while((c = in.read(bytes))!= -1){     
  125.                 out.write(bytes,0,c);     
  126.                 localSize+=c;     
  127.                 long nowProcess = localSize /step;     
  128.                 if(nowProcess > process){     
  129.                     process = nowProcess;     
  130.                     if(process % 10 == 0)     
  131.                         System.out.println("下載進度:"+process);     
  132.                     //TODO 更新文件下載進度,值存放在process變量中     
  133.                 }     
  134.             }     
  135.             in.close();     
  136.             out.close();     
  137.             boolean isDo = ftpClient.completePendingCommand();     
  138.             if(isDo){     
  139.                 result = DownloadStatus.Download_From_Break_Success;     
  140.             }else {     
  141.                 result = DownloadStatus.Download_From_Break_Failed;     
  142.             }     
  143.         }else {     
  144.             OutputStream out = new FileOutputStream(f);     
  145.             InputStream in= ftpClient.retrieveFileStream(new String(remote.getBytes("GBK"),"iso-8859-1"));     
  146.             byte[] bytes = new byte[1024];     
  147.             long step = lRemoteSize /100;     
  148.             long process=0;     
  149.             long localSize = 0L;     
  150.             int c;     
  151.             while((c = in.read(bytes))!= -1){     
  152.                 out.write(bytes, 0, c);     
  153.                 localSize+=c;     
  154.                 long nowProcess = localSize /step;     
  155.                 if(nowProcess > process){     
  156.                     process = nowProcess;     
  157.                     if(process % 10 == 0)     
  158.                         System.out.println("下載進度:"+process);     
  159.                     //TODO 更新文件下載進度,值存放在process變量中     
  160.                 }     
  161.             }     
  162.             in.close();     
  163.             out.close();     
  164.             boolean upNewStatus = ftpClient.completePendingCommand();     
  165.             if(upNewStatus){     
  166.                 result = DownloadStatus.Download_New_Success;     
  167.             }else {     
  168.                 result = DownloadStatus.Download_New_Failed;     
  169.             }     
  170.         }     
  171.         return result;     
  172.     }     
  173.          
  174.     /** *//**   
  175.      * 上傳文件到FTP服務器,支持斷點續傳   
  176.      * @param local 本地文件名稱,絕對路徑   
  177.      * @param remote 遠程文件路徑,使用/home/directory1/subdirectory/file.ext或是 http://www.guihua.org /subdirectory/file.ext 按照Linux上的路徑指定方式,支持多級目錄嵌套,支持遞歸創建不存在的目錄結構   
  178.      * @return 上傳結果   
  179.      * @throws IOException   
  180.      */    
  181.     public UploadStatus upload(String local,String remote) throws IOException{     
  182.         //設置PassiveMode傳輸     
  183.         ftpClient.enterLocalPassiveMode();     
  184.         //設置以二進制流的方式傳輸     
  185.         ftpClient.setFileType(FTP.BINARY_FILE_TYPE);     
  186.         ftpClient.setControlEncoding("GBK");     
  187.         UploadStatus result;     
  188.         //對遠程目錄的處理     
  189.         String remoteFileName = remote;     
  190.         if(remote.contains("/")){     
  191.             remoteFileName = remote.substring(remote.lastIndexOf("/")+1);     
  192.             //創建服務器遠程目錄結構,創建失敗直接返回     
  193.             if(CreateDirecroty(remote, ftpClient)==UploadStatus.Create_Directory_Fail){     
  194.                 return UploadStatus.Create_Directory_Fail;     
  195.             }     
  196.         }     
  197.              
  198.         //檢查遠程是否存在文件     
  199.         FTPFile[] files = ftpClient.listFiles(new String(remoteFileName.getBytes("GBK"),"iso-8859-1"));     
  200.         if(files.length == 1){     
  201.             long remoteSize = files[0].getSize();     
  202.             File f = new File(local);     
  203.             long localSize = f.length();     
  204.             if(remoteSize==localSize){     
  205.                 return UploadStatus.File_Exits;     
  206.             }else if(remoteSize > localSize){     
  207.                 return UploadStatus.Remote_Bigger_Local;     
  208.             }     
  209.                  
  210.             //嘗試移動文件內讀取指針,實現斷點續傳     
  211.             result = uploadFile(remoteFileName, f, ftpClient, remoteSize);     
  212.                  
  213.             //如果斷點續傳沒有成功,則刪除服務器上文件,重新上傳     
  214.             if(result == UploadStatus.Upload_From_Break_Failed){     
  215.                 if(!ftpClient.deleteFile(remoteFileName)){     
  216.                     return UploadStatus.Delete_Remote_Faild;     
  217.                 }     
  218.                 result = uploadFile(remoteFileName, f, ftpClient, 0);     
  219.             }     
  220.         }else {     
  221.             result = uploadFile(remoteFileName, new File(local), ftpClient, 0);     
  222.         }     
  223.         return result;     
  224.     }     
  225.     /** *//**   
  226.      * 斷開與遠程服務器的連接   
  227.      * @throws IOException   
  228.      */    
  229.     public void disconnect() throws IOException{     
  230.         if(ftpClient.isConnected()){     
  231.             ftpClient.disconnect();     
  232.         }     
  233.     }     
  234.          
  235.     /** *//**   
  236.      * 遞歸創建遠程服務器目錄   
  237.      * @param remote 遠程服務器文件絕對路徑   
  238.      * @param ftpClient FTPClient 對象   
  239.      * @return 目錄創建是否成功   
  240.      * @throws IOException   
  241.      */    
  242.     public UploadStatus CreateDirecroty(String remote,FTPClient ftpClient) throws IOException{     
  243.         UploadStatus status = UploadStatus.Create_Directory_Success;     
  244.         String directory = remote.substring(0,remote.lastIndexOf("/")+1);     
  245.         if(!directory.equalsIgnoreCase("/")&&!ftpClient.changeWorkingDirectory(new String(directory.getBytes("GBK"),"iso-8859-1"))){     
  246.             //如果遠程目錄不存在,則遞歸創建遠程服務器目錄     
  247.             int start=0;     
  248.             int end = 0;     
  249.             if(directory.startsWith("/")){     
  250.                 start = 1;     
  251.             }else{     
  252.                 start = 0;     
  253.             }     
  254.             end = directory.indexOf("/",start);     
  255.             while(true){     
  256.                 String subDirectory = new String(remote.substring(start,end).getBytes("GBK"),"iso-8859-1");     
  257.                 if(!ftpClient.changeWorkingDirectory(subDirectory)){     
  258.                     if(ftpClient.makeDirectory(subDirectory)){     
  259.                         ftpClient.changeWorkingDirectory(subDirectory);     
  260.                     }else {     
  261.                         System.out.println("創建目錄失敗");     
  262.                         return UploadStatus.Create_Directory_Fail;     
  263.                     }     
  264.                 }     
  265.                      
  266.                 start = end + 1;     
  267.                 end = directory.indexOf("/",start);     
  268.                      
  269.                 //檢查所有目錄是否創建完畢     
  270.                 if(end <= start){     
  271.                     break;     
  272.                 }     
  273.             }     
  274.         }     
  275.         return status;     
  276.     }     
  277.          
  278.     /** *//**   
  279.      * 上傳文件到服務器,新上傳和斷點續傳   
  280.      * @param remoteFile 遠程文件名,在上傳之前已經將服務器工作目錄做了改變   
  281.      * @param localFile 本地文件 File句柄,絕對路徑   
  282.      * @param processStep 需要顯示的處理進度步進值   
  283.      * @param ftpClient FTPClient 引用   
  284.      * @return   
  285.      * @throws IOException   
  286.      */    
  287.     public UploadStatus uploadFile(String remoteFile,File localFile,FTPClient ftpClient,long remoteSize) throws IOException{     
  288.         UploadStatus status;     
  289.         //顯示進度的上傳     
  290.         long step = localFile.length() / 100;     
  291.         long process = 0;     
  292.         long localreadbytes = 0L;     
  293.         RandomAccessFile raf = new RandomAccessFile(localFile,"r");     
  294.         OutputStream out = ftpClient.appendFileStream(new String(remoteFile.getBytes("GBK"),"iso-8859-1"));     
  295.         //斷點續傳     
  296.         if(remoteSize>0){     
  297.             ftpClient.setRestartOffset(remoteSize);     
  298.             process = remoteSize /step;     
  299.             raf.seek(remoteSize);     
  300.             localreadbytes = remoteSize;     
  301.         }     
  302.         byte[] bytes = new byte[1024];     
  303.         int c;     
  304.         while((c = raf.read(bytes))!= -1){     
  305.             out.write(bytes,0,c);     
  306.             localreadbytes+=c;     
  307.             if(localreadbytes / step != process){     
  308.                 process = localreadbytes / step;     
  309.                 System.out.println("上傳進度:" + process);     
  310.                 //TODO 彙報上傳狀態     
  311.             }     
  312.         }     
  313.         out.flush();     
  314.         raf.close();     
  315.         out.close();     
  316.         boolean result =ftpClient.completePendingCommand();     
  317.         if(remoteSize > 0){     
  318.             status = result?UploadStatus.Upload_From_Break_Success:UploadStatus.Upload_From_Break_Failed;     
  319.         }else {     
  320.             status = result?UploadStatus.Upload_New_File_Success:UploadStatus.Upload_New_File_Failed;     
  321.         }     
  322.         return status;     
  323.     }     
  324.          
  325.       
  326.     @Test   
  327.      
  328. public void run() {   
  329.   // TODO Auto-generated method stub   
  330.       
  331.          try {     
  332.           this.connect(ftpURL, new java.lang.Integer(ftpport), username, pwd);   
  333. //           myFtp.ftpClient.makeDirectory(new String(" 電視劇".getBytes("GBK"),"iso-8859-1"));     
  334. //           myFtp.ftpClient.changeWorkingDirectory(new String(" 電視劇".getBytes("GBK"),"iso-8859-1"));     
  335. //           myFtp.ftpClient.makeDirectory(new String(" 走西口".getBytes("GBK"),"iso-8859-1"));     
  336. //           System.out.println(myFtp.upload("http://www.5a520.cn /yw.flv", "/yw.flv",5));     
  337. //           System.out.println(myFtp.upload("http://www.5a520.cn /走西口24.mp4","/央視走西口/新浪網/走西口 24.mp4"));     
  338.           //   System.out.println(myFtp.download("/ 央視走西口/新浪網/走西口24.mp4", "E:\\走西口242.mp4"));   
  339.             
  340.            this.download(file1, file2);   
  341.          //  System.out.println(myFtp.upload("c:\\a.iso", "/a.iso"));   
  342.              this.disconnect();     
  343.          } catch (IOException e) {     
  344.              System.out.println("連接FTP出錯:"+e.getMessage());     
  345.          }     
  346. }     
  347. }    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章