利用org.apache.commons.net.ftp包實現一個簡單的ftp客戶端實用類。主要實現一下功能 java
1.支持上傳下載。支持斷點續傳 apache
2.支持進度彙報 服務器
3.支持對於中文目錄及中文文件建立的支持。 app
具體請看代碼,上面有詳細的註釋。簡化版本請參見http://zhouzaibao.iteye.com/blog/342766 dom
枚舉類UploadStatus代碼 this
Java代碼
- 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; //刪除遠程文件失敗
- }
枚舉類DownloadStatus代碼 spa
Java代碼
- public enum DownloadStatus {
- Remote_File_Noexist, //遠程文件不存在
- Local_Bigger_Remote, //本地文件大於遠程文件
- Download_From_Break_Success, //斷點下載文件成功
- Download_From_Break_Failed, //斷點下載文件失敗
- Download_New_Success, //全新下載文件成功
- Download_New_Failed; //全新下載文件失敗
- }
核心FTP代碼 .net
Java代碼
- 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 open.mis.data.DownloadStatus;
- import open.mis.data.UploadStatus;
-
- 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;
-
- /**
- * 支持斷點續傳的FTP實用類
- * @author BenZhou
- * @version 0.1 實現基本斷點上傳下載
- * @version 0.2 實現上傳下載進度彙報
- * @version 0.3 實現中文目錄建立及中文文件建立,添加對於中文的支持
- */
- public class ContinueFTP {
- public FTPClient ftpClient = new FTPClient();
-
- public ContinueFTP(){
- //設置將過程當中使用到的命令輸出到控制檯
- this.ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
- }
-
- /**
- * 鏈接到FTP服務器
- * @param hostname 主機名
- * @param port 端口
- * @param username 用戶名
- * @param password 密碼
- * @return 是否鏈接成功
- * @throws IOException
- */
- public boolean connect(String hostname,int port,String username,String password) throws IOException{
- ftpClient.connect(hostname, port);
- ftpClient.setControlEncoding("GBK");
- if(FTPReply.isPositiveCompletion(ftpClient.getReplyCode())){
- if(ftpClient.login(username, password)){
- return true;
- }
- }
- disconnect();
- return false;
- }
-
- /**
- * 從FTP服務器上下載文件,支持斷點續傳,上傳百分比彙報
- * @param remote 遠程文件路徑
- * @param local 本地文件路徑
- * @return 上傳的狀態
- * @throws IOException
- */
- public DownloadStatus download(String remote,String local) throws IOException{
- //設置被動模式
- 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){
- System.out.println("遠程文件不存在");
- return DownloadStatus.Remote_File_Noexist;
- }
-
- 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;
- }
-
- /**
- * 上傳文件到FTP服務器,支持斷點續傳
- * @param local 本地文件名稱,絕對路徑
- * @param remote 遠程文件路徑,使用/home/directory1/subdirectory/file.ext 按照Linux上的路徑指定方式,支持多級目錄嵌套,支持遞歸建立不存在的目錄結構
- * @return 上傳結果
- * @throws IOException
- */
- public UploadStatus upload(String local,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.length == 1){
- long remoteSize = files[0].getSize();
- File f = new File(local);
- long localSize = f.length();
- if(remoteSize==localSize){
- return UploadStatus.File_Exits;
- }else if(remoteSize > localSize){
- return UploadStatus.Remote_Bigger_Local;
- }
-
- //嘗試移動文件內讀取指針,實現斷點續傳
- result = uploadFile(remoteFileName, f, ftpClient, remoteSize);
-
- //若是斷點續傳沒有成功,則刪除服務器上文件,從新上傳
- if(result == UploadStatus.Upload_From_Break_Failed){
- if(!ftpClient.deleteFile(remoteFileName)){
- return UploadStatus.Delete_Remote_Faild;
- }
- result = uploadFile(remoteFileName, f, ftpClient, 0);
- }
- }else {
- result = uploadFile(remoteFileName, new File(local), ftpClient, 0);
- }
- return result;
- }
- /**
- * 斷開與遠程服務器的鏈接
- * @throws IOException
- */
- public void disconnect() throws IOException{
- if(ftpClient.isConnected()){
- ftpClient.disconnect();
- }
- }
-
- /**
- * 遞歸建立遠程服務器目錄
- * @param remote 遠程服務器文件絕對路徑
- * @param ftpClient FTPClient對象
- * @return 目錄建立是否成功
- * @throws IOException
- */
- 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;
- }
-
- /**
- * 上傳文件到服務器,新上傳和斷點續傳
- * @param remoteFile 遠程文件名,在上傳以前已經將服務器工做目錄作了改變
- * @param localFile 本地文件File句柄,絕對路徑
- * @param processStep 須要顯示的處理進度步進值
- * @param ftpClient FTPClient引用
- * @return
- * @throws IOException
- */
- 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;
- if(localreadbytes / step != process){
- process = localreadbytes / step;
- System.out.println("上傳進度:" + process);
- //TODO 彙報上傳狀態
- }
- }
- 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 static void main(String[] args) {
- ContinueFTP myFtp = new ContinueFTP();
- try {
- myFtp.connect("192.168.21.181", 21, "nid", "123");
- // myFtp.ftpClient.makeDirectory(new String("電視劇".getBytes("GBK"),"iso-8859-1"));
- // myFtp.ftpClient.changeWorkingDirectory(new String("電視劇".getBytes("GBK"),"iso-8859-1"));
- // myFtp.ftpClient.makeDirectory(new String("走西口".getBytes("GBK"),"iso-8859-1"));
- // System.out.println(myFtp.upload("E:\\yw.flv", "/yw.flv",5));
- // System.out.println(myFtp.upload("E:\\走西口24.mp4","/央視走西口/新浪網/走西口24.mp4"));
- System.out.println(myFtp.download("/央視走西口/新浪網/走西口24.mp4", "E:\\走西口242.mp4"));
- myFtp.disconnect();
- } catch (IOException e) {
- System.out.println("鏈接FTP出錯:"+e.getMessage());
- }
- }
- }