org.apache.commons.net.ftp包开发FTP客户端,实现断点续传,中文支持

利用org.apache.commons.net.ftp包实现一个简单的ftp客户端实用类。主要实现一下功能

1.支持上传下载。支持断点续传

2.支持进度汇报

3.支持对于中文目录及中文文件创建的支持。

具体请看代码,上面有详细的注释。简化版本请参见http://zhouzaibao.iteye.com/blog/342766

枚举类UploadStatus代码

Java代码   收藏代码
  1. public enum UploadStatus {  
  2.     Create_Directory_Fail,      //远程服务器相应目录创建失败  
  3.     Create_Directory_Success,   //远程服务器闯将目录成功  
  4.     Upload_New_File_Success,    //上传新文件成功  
  5.     Upload_New_File_Failed,     //上传新文件失败  
  6.     File_Exits,                 //文件已经存在  
  7.     Remote_Bigger_Local,        //远程文件大于本地文件  
  8.     Upload_From_Break_Success,  //断点续传成功  
  9.     Upload_From_Break_Failed,   //断点续传失败  
  10.     Delete_Remote_Faild;        //删除远程文件失败  
  11. }  

枚举类DownloadStatus代码

Java代码   收藏代码
  1. public enum DownloadStatus {  
  2.     Remote_File_Noexist,    //远程文件不存在  
  3.     Local_Bigger_Remote,    //本地文件大于远程文件  
  4.     Download_From_Break_Success,    //断点下载文件成功  
  5.     Download_From_Break_Failed,     //断点下载文件失败  
  6.     Download_New_Success,           //全新下载文件成功  
  7.     Download_New_Failed;            //全新下载文件失败  
  8. }  

 

核心FTP代码

Java代码   收藏代码
  1. import java.io.File;  
  2. import java.io.FileOutputStream;  
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.io.OutputStream;  
  6. import java.io.PrintWriter;  
  7. import java.io.RandomAccessFile;  
  8.   
  9. import open.mis.data.DownloadStatus;  
  10. import open.mis.data.UploadStatus;  
  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.   
  18. /** 
  19.  * 支持断点续传的FTP实用类 
  20.  * @author BenZhou 
  21.  * @version 0.1 实现基本断点上传下载 
  22.  * @version 0.2 实现上传下载进度汇报 
  23.  * @version 0.3 实现中文目录创建及中文文件创建,添加对于中文的支持 
  24.  */  
  25. public class ContinueFTP {  
  26.     public FTPClient ftpClient = new FTPClient();  
  27.       
  28.     public ContinueFTP(){  
  29.         //设置将过程中使用到的命令输出到控制台  
  30.         this.ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));  
  31.     }  
  32.       
  33.     /** 
  34.      * 连接到FTP服务器 
  35.      * @param hostname 主机名 
  36.      * @param port 端口 
  37.      * @param username 用户名 
  38.      * @param password 密码 
  39.      * @return 是否连接成功 
  40.      * @throws IOException 
  41.      */  
  42.     public boolean connect(String hostname,int port,String username,String password) throws IOException{  
  43.         ftpClient.connect(hostname, port);  
  44.         ftpClient.setControlEncoding("GBK");  
  45.         if(FTPReply.isPositiveCompletion(ftpClient.getReplyCode())){  
  46.             if(ftpClient.login(username, password)){  
  47.                 return true;  
  48.             }  
  49.         }  
  50.         disconnect();  
  51.         return false;  
  52.     }  
  53.       
  54.     /** 
  55.      * 从FTP服务器上下载文件,支持断点续传,上传百分比汇报 
  56.      * @param remote 远程文件路径 
  57.      * @param local 本地文件路径 
  58.      * @return 上传的状态 
  59.      * @throws IOException 
  60.      */  
  61.     public DownloadStatus download(String remote,String local) throws IOException{  
  62.         //设置被动模式  
  63.         ftpClient.enterLocalPassiveMode();  
  64.         //设置以二进制方式传输  
  65.         ftpClient.setFileType(FTP.BINARY_FILE_TYPE);  
  66.         DownloadStatus result;  
  67.           
  68.         //检查远程文件是否存在  
  69.         FTPFile[] files = ftpClient.listFiles(new String(remote.getBytes("GBK"),"iso-8859-1"));  
  70.         if(files.length != 1){  
  71.             System.out.println("远程文件不存在");  
  72.             return DownloadStatus.Remote_File_Noexist;  
  73.         }  
  74.           
  75.         long lRemoteSize = files[0].getSize();  
  76.         File f = new File(local);  
  77.         //本地存在文件,进行断点下载  
  78.         if(f.exists()){  
  79.             long localSize = f.length();  
  80.             //判断本地文件大小是否大于远程文件大小  
  81.             if(localSize >= lRemoteSize){  
  82.                 System.out.println("本地文件大于远程文件,下载中止");  
  83.                 return DownloadStatus.Local_Bigger_Remote;  
  84.             }  
  85.               
  86.             //进行断点续传,并记录状态  
  87.             FileOutputStream out = new FileOutputStream(f,true);  
  88.             ftpClient.setRestartOffset(localSize);  
  89.             InputStream in = ftpClient.retrieveFileStream(new String(remote.getBytes("GBK"),"iso-8859-1"));  
  90.             byte[] bytes = new byte[1024];  
  91.             long step = lRemoteSize /100;  
  92.             long process=localSize /step;  
  93.             int c;  
  94.             while((c = in.read(bytes))!= -1){  
  95.                 out.write(bytes,0,c);  
  96.                 localSize+=c;  
  97.                 long nowProcess = localSize /step;  
  98.                 if(nowProcess > process){  
  99.                     process = nowProcess;  
  100.                     if(process % 10 == 0)  
  101.                         System.out.println("下载进度:"+process);  
  102.                     //TODO 更新文件下载进度,值存放在process变量中  
  103.                 }  
  104.             }  
  105.             in.close();  
  106.             out.close();  
  107.             boolean isDo = ftpClient.completePendingCommand();  
  108.             if(isDo){  
  109.                 result = DownloadStatus.Download_From_Break_Success;  
  110.             }else {  
  111.                 result = DownloadStatus.Download_From_Break_Failed;  
  112.             }  
  113.         }else {  
  114.             OutputStream out = new FileOutputStream(f);  
  115.             InputStream in= ftpClient.retrieveFileStream(new String(remote.getBytes("GBK"),"iso-8859-1"));  
  116.             byte[] bytes = new byte[1024];  
  117.             long step = lRemoteSize /100;  
  118.             long process=0;  
  119.             long localSize = 0L;  
  120.             int c;  
  121.             while((c = in.read(bytes))!= -1){  
  122.                 out.write(bytes, 0, c);  
  123.                 localSize+=c;  
  124.                 long nowProcess = localSize /step;  
  125.                 if(nowProcess > process){  
  126.                     process = nowProcess;  
  127.                     if(process % 10 == 0)  
  128.                         System.out.println("下载进度:"+process);  
  129.                     //TODO 更新文件下载进度,值存放在process变量中  
  130.                 }  
  131.             }  
  132.             in.close();  
  133.             out.close();  
  134.             boolean upNewStatus = ftpClient.completePendingCommand();  
  135.             if(upNewStatus){  
  136.                 result = DownloadStatus.Download_New_Success;  
  137.             }else {  
  138.                 result = DownloadStatus.Download_New_Failed;  
  139.             }  
  140.         }  
  141.         return result;  
  142.     }  
  143.       
  144.     /** 
  145.      * 上传文件到FTP服务器,支持断点续传 
  146.      * @param local 本地文件名称,绝对路径 
  147.      * @param remote 远程文件路径,使用/home/directory1/subdirectory/file.ext 按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构 
  148.      * @return 上传结果 
  149.      * @throws IOException 
  150.      */  
  151.     public UploadStatus upload(String local,String remote) throws IOException{  
  152.         //设置PassiveMode传输  
  153.         ftpClient.enterLocalPassiveMode();  
  154.         //设置以二进制流的方式传输  
  155.         ftpClient.setFileType(FTP.BINARY_FILE_TYPE);  
  156.         ftpClient.setControlEncoding("GBK");  
  157.         UploadStatus result;  
  158.         //对远程目录的处理  
  159.         String remoteFileName = remote;  
  160.         if(remote.contains("/")){  
  161.             remoteFileName = remote.substring(remote.lastIndexOf("/")+1);  
  162.             //创建服务器远程目录结构,创建失败直接返回  
  163.             if(CreateDirecroty(remote, ftpClient)==UploadStatus.Create_Directory_Fail){  
  164.                 return UploadStatus.Create_Directory_Fail;  
  165.             }  
  166.         }  
  167.           
  168.         //检查远程是否存在文件  
  169.         FTPFile[] files = ftpClient.listFiles(new String(remoteFileName.getBytes("GBK"),"iso-8859-1"));  
  170.         if(files.length == 1){  
  171.             long remoteSize = files[0].getSize();  
  172.             File f = new File(local);  
  173.             long localSize = f.length();  
  174.             if(remoteSize==localSize){  
  175.                 return UploadStatus.File_Exits;  
  176.             }else if(remoteSize > localSize){  
  177.                 return UploadStatus.Remote_Bigger_Local;  
  178.             }  
  179.               
  180.             //尝试移动文件内读取指针,实现断点续传  
  181.             result = uploadFile(remoteFileName, f, ftpClient, remoteSize);  
  182.               
  183.             //如果断点续传没有成功,则删除服务器上文件,重新上传  
  184.             if(result == UploadStatus.Upload_From_Break_Failed){  
  185.                 if(!ftpClient.deleteFile(remoteFileName)){  
  186.                     return UploadStatus.Delete_Remote_Faild;  
  187.                 }  
  188.                 result = uploadFile(remoteFileName, f, ftpClient, 0);  
  189.             }  
  190.         }else {  
  191.             result = uploadFile(remoteFileName, new File(local), ftpClient, 0);  
  192.         }  
  193.         return result;  
  194.     }  
  195.     /** 
  196.      * 断开与远程服务器的连接 
  197.      * @throws IOException 
  198.      */  
  199.     public void disconnect() throws IOException{  
  200.         if(ftpClient.isConnected()){  
  201.             ftpClient.disconnect();  
  202.         }  
  203.     }  
  204.       
  205.     /** 
  206.      * 递归创建远程服务器目录 
  207.      * @param remote 远程服务器文件绝对路径 
  208.      * @param ftpClient FTPClient对象 
  209.      * @return 目录创建是否成功 
  210.      * @throws IOException 
  211.      */  
  212.     public UploadStatus CreateDirecroty(String remote,FTPClient ftpClient) throws IOException{  
  213.         UploadStatus status = UploadStatus.Create_Directory_Success;  
  214.         String directory = remote.substring(0,remote.lastIndexOf("/")+1);  
  215.         if(!directory.equalsIgnoreCase("/")&&!ftpClient.changeWorkingDirectory(new String(directory.getBytes("GBK"),"iso-8859-1"))){  
  216.             //如果远程目录不存在,则递归创建远程服务器目录  
  217.             int start=0;  
  218.             int end = 0;  
  219.             if(directory.startsWith("/")){  
  220.                 start = 1;  
  221.             }else{  
  222.                 start = 0;  
  223.             }  
  224.             end = directory.indexOf("/",start);  
  225.             while(true){  
  226.                 String subDirectory = new String(remote.substring(start,end).getBytes("GBK"),"iso-8859-1");  
  227.                 if(!ftpClient.changeWorkingDirectory(subDirectory)){  
  228.                     if(ftpClient.makeDirectory(subDirectory)){  
  229.                         ftpClient.changeWorkingDirectory(subDirectory);  
  230.                     }else {  
  231.                         System.out.println("创建目录失败");  
  232.                         return UploadStatus.Create_Directory_Fail;  
  233.                     }  
  234.                 }  
  235.                   
  236.                 start = end + 1;  
  237.                 end = directory.indexOf("/",start);  
  238.                   
  239.                 //检查所有目录是否创建完毕  
  240.                 if(end <= start){  
  241.                     break;  
  242.                 }  
  243.             }  
  244.         }  
  245.         return status;  
  246.     }  
  247.       
  248.     /** 
  249.      * 上传文件到服务器,新上传和断点续传 
  250.      * @param remoteFile 远程文件名,在上传之前已经将服务器工作目录做了改变 
  251.      * @param localFile 本地文件File句柄,绝对路径 
  252.      * @param processStep 需要显示的处理进度步进值 
  253.      * @param ftpClient FTPClient引用 
  254.      * @return 
  255.      * @throws IOException 
  256.      */  
  257.     public UploadStatus uploadFile(String remoteFile,File localFile,FTPClient ftpClient,long remoteSize) throws IOException{  
  258.         UploadStatus status;  
  259.         //显示进度的上传  
  260.         long step = localFile.length() / 100;  
  261.         long process = 0;  
  262.         long localreadbytes = 0L;  
  263.         RandomAccessFile raf = new RandomAccessFile(localFile,"r");  
  264.         OutputStream out = ftpClient.appendFileStream(new String(remoteFile.getBytes("GBK"),"iso-8859-1"));  
  265.         //断点续传  
  266.         if(remoteSize>0){  
  267.             ftpClient.setRestartOffset(remoteSize);  
  268.             process = remoteSize /step;  
  269.             raf.seek(remoteSize);  
  270.             localreadbytes = remoteSize;  
  271.         }  
  272.         byte[] bytes = new byte[1024];  
  273.         int c;  
  274.         while((c = raf.read(bytes))!= -1){  
  275.             out.write(bytes,0,c);  
  276.             localreadbytes+=c;  
  277.             if(localreadbytes / step != process){  
  278.                 process = localreadbytes / step;  
  279.                 System.out.println("上传进度:" + process);  
  280.                 //TODO 汇报上传状态  
  281.             }  
  282.         }  
  283.         out.flush();  
  284.         raf.close();  
  285.         out.close();  
  286.         boolean result =ftpClient.completePendingCommand();  
  287.         if(remoteSize > 0){  
  288.             status = result?UploadStatus.Upload_From_Break_Success:UploadStatus.Upload_From_Break_Failed;  
  289.         }else {  
  290.             status = result?UploadStatus.Upload_New_File_Success:UploadStatus.Upload_New_File_Failed;  
  291.         }  
  292.         return status;  
  293.     }  
  294.       
  295.     public static void main(String[] args) {  
  296.         ContinueFTP myFtp = new ContinueFTP();  
  297.         try {  
  298.             myFtp.connect("192.168.21.181"21"nid""123");  
  299. //          myFtp.ftpClient.makeDirectory(new String("电视剧".getBytes("GBK"),"iso-8859-1"));  
  300. //          myFtp.ftpClient.changeWorkingDirectory(new String("电视剧".getBytes("GBK"),"iso-8859-1"));  
  301. //          myFtp.ftpClient.makeDirectory(new String("走西口".getBytes("GBK"),"iso-8859-1"));  
  302. //          System.out.println(myFtp.upload("E:\\yw.flv", "/yw.flv",5));  
  303. //          System.out.println(myFtp.upload("E:\\走西口24.mp4","/央视走西口/新浪网/走西口24.mp4"));  
  304.             System.out.println(myFtp.download("/央视走西口/新浪网/走西口24.mp4""E:\\走西口242.mp4"));  
  305.             myFtp.disconnect();  
  306.         } catch (IOException e) {  
  307.             System.out.println("连接FTP出错:"+e.getMessage());  
  308.         }  
  309.     }  
  310. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值