加強的Java FTP工具----擴展免費版的edtftpj

加強的Java FTP工具----擴展免費版的edtftpj
 
edtftpjs是國外的一個公司所作。有免費版、企業版之分,還有不用語言的版本。商業版的功能強大,是很是優秀的FTP組建。免費的湊合能用,可是功能相對簡單,實現粗糙。使用起來問題多多。
 
爲了讓免費版的edtftpj工具也具備商業版的一些強勁功能,本人利用業餘時間作了擴展,通過測試能夠正常使用。其中的算法也許不是最好,也歡迎高人提供更好的算法。
 
擴展的主要圍繞最經常使用的功能來進行:
一、加強上傳下載功能,使其支持文件和文件夾,若是是文件夾,上傳下載保持源的目錄結構。
二、加強判斷文件、文件夾是否存在的方法,使得ftp的文件操做如本地文件File操做同樣容易。
三、添加判斷是否爲文件、是否爲目錄的方法。
四、增長FTP配置管理的工具實現,這個不是主要的,就不貼了。
 
環境:
Java SE 1.5
edtftpjs-2.03 free版
 
 
實現思路:
繼承FTP客戶端核心的類com.enterprisedt.net.ftp.FileTransferClient,添加一些更爲通用的有效的方法。自己考慮到覆蓋,感受不妥。就擴展吧!
 
實現代碼:
import com.enterprisedt.net.ftp.FTPException;
import com.enterprisedt.net.ftp.FileTransferClient;
import com.enterprisedt.net.ftp.WriteMode;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import zzvcom.cms.ccm.commons.StringTookit;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;

/**
* FTP加強工具
*
* @author leizhimin 2008-12-13 16:13:01
*/

public class UltraFTPClient extends FileTransferClient {
         private static Log log = LogFactory.getLog(UltraFTPClient. class);

         public UltraFTPClient() {
        }

         /**
         * 下載文件(夾),在本地保持FTP上的目錄結構
         *
         * @param localFolderPath 本地存放文件夾
         * @param remotePath            遠程文件(夾)路徑
         * @param remoteSubPath     遠程文件存放相對根目錄
         * @throws FTPException
         * @throws IOException
         */

         public void ftpDownload( final String localFolderPath, final String remotePath, String remoteSubPath) throws FTPException, IOException, ParseException {
                 if (isDir(remoteSubPath)) {
                        String localPath = localFolderPath + StringTookit.getRelativeRootPath(remoteSubPath, StringTookit.getParentPath(remotePath));
                         if (! new File(localPath).exists())
                                 new File(localPath).mkdirs();
                        String[] x = directoryNameList(remoteSubPath, false);
                         for (String fname : x) {
                                String rmFilePath = StringTookit.formatPath(remoteSubPath + "/" + fname);
                                 if (isDir(rmFilePath)) {
                                        ftpDownload(localFolderPath, remotePath, rmFilePath);
                                } else {
                                        String _localPath = localFolderPath + "/" +
                                                        StringTookit.getRelativeRootPath(rmFilePath, StringTookit.getParentPath(remotePath));
                                        downloadFile(_localPath, rmFilePath, WriteMode.OVERWRITE);
                                }
                        }
                } else if (isFile(remotePath)) {
                        String localPath = localFolderPath + StringTookit.getRelativeRootPath(remoteSubPath, remotePath);
                        downloadFile(localPath, remoteSubPath, WriteMode.OVERWRITE);
                } else {
                        log.error( "所下載的文件或文件夾不存在,請檢查!");
                }
                log.info( "FTP下載從服務器上的" + remoteSubPath + "下載到本地" + localFolderPath + "結束!");
        }

         /**
         * 上傳文件(夾),在FTP上保持本地的目錄結構
         *
         * @param localFile         本地文件
         * @param localFilePath 本地文件的路徑
         * @param remoteSubPath 遠程文件存放相對根目錄
         * @throws IOException
         * @throws FTPException
         */

         public void ftpUpload(File localFile, final String localFilePath, final String remoteSubPath) throws IOException, FTPException {
                 if (localFile.isDirectory()) {
                         for (File file : localFile.listFiles()) {
                                 if (file.isDirectory()) {
                                        String remotePath = StringTookit.formatPath(remoteSubPath) + StringTookit.getRelativeRootPath(file.getPath(), StringTookit.getParentPath(localFilePath));
                                        log.info(remotePath);
                                         if (!isExist(remotePath)) createDirectory(remotePath);
                                        ftpUpload(file, localFilePath, remoteSubPath);
                                } else {
                                        String remotePath = StringTookit.formatPath(remoteSubPath) +
                                                        StringTookit.getRelativeRootPath(file.getPath(), StringTookit.getParentPath(localFilePath));
                                        uploadFile(file.getPath(), remotePath, WriteMode.APPEND);
                                }
                        }
                } else if (localFile.isFile()) {
                        String remotePath = StringTookit.formatPath(remoteSubPath) +
                                        StringTookit.getRelativeRootPath(localFile.getPath(), StringTookit.getParentPath(localFilePath));
                         if (!isExist(StringTookit.getParentPath(remotePath)))
                                createDirectory(StringTookit.getParentPath(remotePath));
                        System.out.println(remotePath);
                        uploadFile(localFile.getPath(), remotePath, WriteMode.APPEND);
                }
                log.info( "FTP上傳" + localFile.getPath() + "到" + remoteSubPath + "目錄下結束!");
        }

         /**
         * @param remotePath 遠程文件(夾)路徑
         * @return 遠程的文件(夾)資源是否存在
         */

         public boolean isExist(String remotePath) {
                 boolean flag = true;
                 try {
                        directoryList(remotePath);
                } catch (Exception e) {
                        flag = false;
                }
                 return flag;
        }

         /**
         * @param remotePath 遠程文件(夾)路徑
         * @return 當遠程資源存在且爲文件時返回ture,不然返回false
         */


         public boolean isFile(String remotePath) {
                 try {
                         int size = directoryList(remotePath).length;
                         if (size >= 0) {
                                 if (exists(remotePath)) {
                                         return true;
                                }
                        }
                } catch (Exception e) {
                }
                 return false;
        }

         /**
         * @param remotePath 遠程文件(夾)路徑
         * @return 當遠程資源存在且爲文件夾時返回ture,不然返回false
         */

         public boolean isDir(String remotePath) {
                 try {
                         int size = directoryList(remotePath).length;
                         if (size >= 0) {
                                 if (exists(remotePath)) {
                                         return false;
                                } else {
                                         return true;
                                }
                        }
                } catch (Exception e) {
                }
                 return false;
        }
}
 
 
爲了支持目錄運算與不一樣操做系統的兼容性,寫了一個文件路徑處理工具。有了這一整套的工具後,上面的工做才能更清晰的去作。
/**
* 字符串工具箱
*
* @author leizhimin 2008-12-15 22:40:12
*/

public final class StringTookit {
         /**
         * 將一個字符串的首字母改成大寫或者小寫
         *
         * @param srcString 源字符串
         * @param flag            大小寫標識,ture小寫,false大些
         * @return 改寫後的新字符串
         */

         public static String toLowerCaseInitial(String srcString, boolean flag) {
                StringBuilder sb = new StringBuilder();
                 if (flag) {
                        sb.append(Character.toLowerCase(srcString.charAt(0)));
                } else {
                        sb.append(Character.toUpperCase(srcString.charAt(0)));
                }
                sb.append(srcString.substring(1));
                 return sb.toString();
        }

         /**
         * 將一個字符串按照句點(.)分隔,返回最後一段
         *
         * @param clazzName 源字符串
         * @return 句點(.)分隔後的最後一段字符串
         */

         public static String getLastName(String clazzName) {
                String[] ls = clazzName.split( "\\.");
                 return ls[ls.length - 1];
        }

         /**
         * 格式化文件路徑,將其中不規範的分隔轉換爲標準的分隔符,而且去掉末尾的"/"符號。
         *
         * @param path 文件路徑
         * @return 格式化後的文件路徑
         */

         public static String formatPath(String path) {
                String reg = "\\\\+|/+";
                String temp = path.trim().replaceAll(reg, "/");
                 if (temp.endsWith( "/")) {
                         return temp.substring(0, temp.length() - 1);
                }
                 return temp;
        }

         /**
         * 獲取文件父路徑
         *
         * @param path 文件路徑
         * @return 文件父路徑
         */

         public static String getParentPath(String path) {
                 return new File(path).getParent();
        }

         /**
         * 獲取相對路徑
         *
         * @param fullPath 全路徑
         * @param rootPath 根路徑
         * @return 相對根路徑的相對路徑
         */

         public static String getRelativeRootPath(String fullPath, String rootPath) {
                String relativeRootPath = null;
                String _fullPath = formatPath(fullPath);
                String _rootPath = formatPath(rootPath);

                 if (_fullPath.startsWith(_rootPath)) {
                        relativeRootPath = fullPath.substring(_rootPath.length());
                } else {
                         throw new RuntimeException( "要處理的兩個字符串沒有包含關係,處理失敗!");
                }
                 if (relativeRootPath == null) return null;
                 else
                         return formatPath(relativeRootPath);
        }
}
 
FTP客戶端配置工具:
一個好的工具,配置也很講究,這裏也不例外,通過精心處理,FTP服務器配置變得輕鬆自如:
import com.enterprisedt.net.ftp.FTPConnectMode;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import zzvcom.cms.ccm.commons.JavaXmlTookit;
import zzvcom.cms.ccm.commons.SysParamsTookit;

/**
* FTP配置
*
* @author leizhimin 2008-12-5 22:49:39
*/

public class FtpServerConfigration {
         private static final Log log = LogFactory.getLog(FtpServerConfigration. class);
         private String username;                 //用戶名
         private String password;                 //密碼
         private String ip;                             //ip
         private Integer port;                     //端口
         private Integer timeout;                 //超時時間
         private Integer buffersize;         //緩存大小
         private Integer notifytime;         //通知時間
         private String connectMode;         //鏈接模式
         private String encoding;                 //編碼方式

         public FtpServerConfigration(String username, String password, String ip, Integer port) {
                 this.username = username;
                 this.password = password;
                 this.ip = ip;
                 this.port = port;
                 this.timeout = Integer.valueOf(SysParamsTookit.getProperty( "timeout", "36000000"));
                 this.buffersize = Integer.valueOf(SysParamsTookit.getProperty( "buffersize", "2048000"));
                 this.notifytime = Integer.valueOf(SysParamsTookit.getProperty( "notifytime", "5000"));
                 this.connectMode = SysParamsTookit.getProperty( "connectMode", "PASV");
                 this.encoding = SysParamsTookit.getProperty( "encoding", "GBK");
        }

         public FtpServerConfigration(String ftpConfigXml) {
                FtpServerConfigration config = (FtpServerConfigration) JavaXmlTookit.xml2Java(ftpConfigXml, FtpServerConfigration. class);
                 if (StringUtils.isBlank(config.getUsername())
                                || StringUtils.isBlank(config.getPassword())
                                || StringUtils.isBlank(config.getIp())
                                || config.getPort() == null) {
                        log.error( "FTP最基本的配置屬性(username、password、ip、port)不能爲空,請檢查!");
                } else {
                         this.username = config.getUsername();
                         this.password = config.getPassword();
                         this.ip = config.getIp();
                         this.port = config.getPort();
                }
                 if (config.getTimeout() == null)
                         this.timeout = Integer.valueOf(SysParamsTookit.getProperty( "timeout", "36000000"));
                 if (config.getBuffersize() == null)
                         this.buffersize = Integer.valueOf(SysParamsTookit.getProperty( "buffersize", "2048000"));
                 if (config.getNotifytime() == null)
                         this.notifytime = Integer.valueOf(SysParamsTookit.getProperty( "notifytime", "5000"));
                 if (StringUtils.isBlank(config.getConnectMode()))
                         this.connectMode = SysParamsTookit.getProperty( "connectMode", "PASV");
                 if (StringUtils.isBlank(config.getEncoding()))
                         this.encoding = SysParamsTookit.getProperty( "encoding", "GBK");
        }

         /**
         * 獲取當前FTP鏈接配置
         *
         * @return 當前FTP鏈接配置
         */

         public FtpServerConfigration getConfigration() {
                 return this;
        }

         /**
         * 構建FTP客戶端鏈接,並進行鏈接
         *
         * @return FTP客戶端鏈接
         * @throws Exception 當構建客戶端失敗時拋出
         */

         public UltraFTPClient buildFtpClient() throws Exception {
                UltraFTPClient client = new UltraFTPClient();
                 try {
                        client.setUserName(username);
                        client.setPassword(password);
                        client.setRemoteHost(ip);
                        client.setRemotePort(port);
                        client.setTimeout(timeout);
                        client.getAdvancedSettings().setTransferBufferSize(buffersize);
                        client.getAdvancedSettings().setTransferNotifyInterval(notifytime);
                        client.getAdvancedSettings().setControlEncoding(encoding); 
                       // client.setEventListener( new UploadListener(client));                 //設置事件監聽器
                         if (connectMode.equalsIgnoreCase( "ACTIVE")) {
                                client.getAdvancedFTPSettings().setConnectMode(FTPConnectMode.ACTIVE); //設置爲被動模式
                        } else if (connectMode.equalsIgnoreCase( "PASV")) {
                                client.getAdvancedFTPSettings().setConnectMode(FTPConnectMode.PASV); //設置爲被動模式
                        } else {
                                log.error( "標識爲" + connectMode + "的FTP鏈接模式配置錯誤,鏈接模式僅有兩種ACTIVE和PASV,請檢查!");
                        }
                        client.connect();
                        log.info( "FTP鏈接成功!詳細信息(遠程主機:" + ip + ",用戶名:" + username + ")");
                } catch (Exception e) {
                        log.info( "FTP建立鏈接發生異常!", e);
                         throw e;
                }
                 return client;
        }

         public String getUsername() {
                 return username;
        }

         public void setUsername(String username) {
                 this.username = username;
        }

         public String getPassword() {
                 return password;
        }

         public void setPassword(String password) {
                 this.password = password;
        }

         public String getIp() {
                 return ip;
        }

         public void setIp(String ip) {
                 this.ip = ip;
        }

         public Integer getPort() {
                 return port;
        }

         public void setPort(Integer port) {
                 this.port = port;
        }

         public Integer getTimeout() {
                 return timeout;
        }

         public void setTimeout(Integer timeout) {
                 this.timeout = timeout;
        }

         public Integer getBuffersize() {
                 return buffersize;
        }

         public void setBuffersize(Integer buffersize) {
                 this.buffersize = buffersize;
        }

         public Integer getNotifytime() {
                 return notifytime;
        }

         public void setNotifytime(Integer notifytime) {
                 this.notifytime = notifytime;
        }

         public String getConnectMode() {
                 return connectMode;
        }

         public void setConnectMode(String connectMode) {
                 this.connectMode = connectMode;
        }

         public String getEncoding() {
                 return encoding;
        }

         public void setEncoding(String encoding) {
                 this.encoding = encoding;
        }
}
 
系統默認的FtP參數配置:
### FTP默認配置參數 ###
# FTP鏈接模式:ACTIVE,PASV爲兩種鏈接模式
#port=21
ftp.timeout=360000
ftp.buffersize=20480
ftp.notifytime=5000
ftp.connectMode=PASV
ftp.encoding=GBK
 
進行測試:
這裏只給出測試大概過程:
一、建立一個FTP配置對象,並從FTP配置對象構建一個加強的FTP客戶端對象。
UltraFTPClient client = new FtpServerConfigration("testuser", "123456", "192.168.0.2", 21).buildFtpClient();
 
二、根據有了客戶端後,就能夠調用加強的和原有的任何方法,來完成你想要的FTP操做。
 
三、操做完成後關閉FTP鏈接。
client.disconnect();
 
遺留問題:
FTP的寫模式在下載的時候沒法指定,指定爲WriteMode.APPEND(追加)是最理想的,可是如今沒法作到,只要設置就出錯。也許是由於我服務器配置的問題,緣由不明。
若是您解決了遺留問題,或者發現了新的問題,也請留言告訴我。
 
題外話:
下一步本人將利用業餘時間使用Apache的Commons Net提供的基礎API來實現這個FTP客戶端。
一我的的精力和能力都是有限的,但願這個FTP客戶端未來能成爲一個頗受歡迎的開源組件,任何人均可以輕鬆使用其構建本身的FTP應用。
相關文章
相關標籤/搜索