论坛首页 Java企业应用论坛

方便的FTP客户端封装(apache.commons.net.ftp)

浏览 8153 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (9) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-08-05  
每次在javaeye聆听诸位达人的教诲时,心里总想着啥时候我也能奉献一段代码,哪怕是那么简陋,于是今天我就贴一段代码上来,欢迎大家一起讨论,以共同学习为目标。

这段代码是对apache.commons.net.ftp的一个封装。

封装原因:项目中多处使用apache.commons.net.ftp时不方便

封装后的功能:
1.统一配置客户端建立连接,项目中直接调用ftp操作函数
2.可以选择手动控制连接,亦可选择自动控制连接
3.现有的功能:上传、下载、列表、删除

具体使用后面我会贴出一个测试类。

现在开始贴代码:

一、FTP客户端封装主类
/**
 * 
 *  FTP客户端
 *
 * @author bleet (mailto:liuqiang2004456@163.com)
 */
public class FtpClient {
	private FTPClient client = null;
	
	private static FtpClient instance = null;
	
	private FtpClientConfig config = null;
	
	private Logger log = null;
	
	/** 当前工作目录,每次关闭连接要回复到null,因为当前类是单例类 */
	private String workDirectory = null;
	
	/** 是否手工控制连接 */
	private boolean handSwitch = false;
	
	/** true表示已经登录到ftp服务器 */
	private boolean ready = false;

	/**
	 *  初始化参数配置及创建commons.net.ftp的客户端
	 *
	 */
	private FtpClient(String configFile){
		log = Logger.getLogger(getClass());
		client = new FTPClient();
		config = FtpClientConfig.getInstance(configFile);
		
		/** 日志输出 */
		client.addProtocolCommandListener( new  PrintCommandListener( new  PrintWriter(System.out)));
		client.setControlEncoding(config.getRemoteEncoding());
		
		// 设置当前工作目录
		workDirectory = config.getRootPath();
	}
	
	/**
	 *  获取ftp客户端的实例
	 * @return
	 */
	public static FtpClient getInstance(String configFile) {
		if(instance == null) instance = new FtpClient(configFile);
		return instance;
	}
	
	/**
	 *  连接ftp
	 * @return
	 * @throws SocketException
	 * @throws IOException
	 */
	private boolean connect() throws SocketException, IOException {
		client.connect(config.getServer(), Integer.valueOf(config.getPort()));
		int reply;
		reply = client.getReplyCode();

        if (!FTPReply.isPositiveCompletion(reply)){
        	client.disconnect();
            log.info("FTP server refused connection.");
            return false;
        }
        return true;
	}
	
	/**
	 * 登入ftp
	 * @return
	 * @throws IOException
	 */
	private boolean login() throws IOException{
		if (!client.login(config.getUsername(), config.getPassword())) {
			client.logout();
			log.info("FTP server login fail.");
			return false;
		}
		return true;
	}
	
	/**
	 * 连接然后登入统一入口
	 * @return
	 * @throws SocketException
	 * @throws IOException
	 */
	public boolean ready() throws SocketException, IOException {
		if(connect() && login()){
			setConfig();
			ready = true;
			return true;
		}
		return false;
	}
	
	/**
	 *  ftp运行环境参数配置
	 * @throws IOException
	 */
	private void setConfig() throws IOException{
		FTPClientConfig conf = new FTPClientConfig(config.getFTPStyle());
		client.configure(conf);
		
		// 被动传输模式
		if(config.getPassiveMode())
			client.enterLocalPassiveMode();
		
		// 二进制传输模式
		if (config.getBinaryFileType())
			client.setFileType(FTP.BINARY_FILE_TYPE);
		
		// 设置当前工作目录
		client.changeWorkingDirectory(getWorkDirectory());
	}
	
	/**
	 * 关闭连接
	 * @throws IOException
	 */
	public void close() throws IOException {
		if(client.isConnected()){
			client.logout();
			client.disconnect();
			
			// 也可设置为null
			workDirectory = config.getRootPath();
		}
		ready = false;
	}
	
	/**
	 * 获取等前工作目录的文件列表
	 * @return
	 * @throws IOException
	 */
	public String[] listFiles() throws IOException {
		if (!setReady()) {
			return null;
		}
		FTPFile[] files = client.listFiles();
		int filesLength = files.length;
		String[] fileNameArr = new String[filesLength];
		for (int i = 0; i < filesLength; i++) {
			fileNameArr[i] = files[i].getName();
		}
		setClose();
		return fileNameArr;
	}
	
	/**
	 * 上传文件,文件名方式
	 * @param path
	 * @param name
	 * @return
	 * @throws IOException
	 */
	public boolean upload(String path, String name, String remoteName) throws IOException {
		if (!setReady()) {
			return false;
		}
        FileInputStream fis = new FileInputStream(path+name);
        if(client.storeFile(getWorkDirectory()+remoteName, fis)){
        	log.info(" upload success !!! ");
        	fis.close();
        	setClose();
        	return true;
        }
        fis.close();
        setClose();
        log.info(" upload fail !!! ");
		return false;
	}
	
	/**
	 * 上传文件,流方式
	 * @param path
	 * @param name
	 * @return
	 * @throws IOException
	 */
	public boolean upload (InputStream stream, String name, String remoteName) throws IOException {
		if (!setReady()) {
			return false;
		}
        if(client.storeFile(getWorkDirectory() + remoteName, stream)){
        	log.info(" upload success !!! ");
        	stream.close();
        	setClose();
        	return true;
        }
        stream.close();
        setClose();
        log.info(" upload fail !!! ");
		return false;
	}
	
	/**
	 *  下载文件
	 * @param path
	 * @param name
	 * @return
	 * @throws UnsupportedEncodingException
	 * @throws IOException
	 */
	public boolean download (String path, String name) throws UnsupportedEncodingException, IOException {
		if (!setReady()) {
			return false;
		}
		FileOutputStream fos = new FileOutputStream(path + name);

		if (client.retrieveFile(new String(name.getBytes(config.getLocalEncoding()),config.getRemoteEncoding()), fos)) {
			log.info("download success !!! ");
			fos.close();
			setClose();
			return true;
		}
		fos.close();
		setClose();
		log.info(" download fail !!! ");
		return false;
	}
	
	/**
	 *  删除文件
	 * @param path
	 * @param name
	 * @return
	 * @throws IOException
	 */
	public boolean removeFile(String path, String name) throws IOException {
		if (!setReady()) {
			return false;
		}
		client.changeWorkingDirectory(config.getRootPath()+path);
		if(client.deleteFile(name)){
			log.info("remove file success !!! ");
			setClose();
			return true;
		}
		setClose();
		log.info(" remove file fail !!! ");
		return false;
	}
	
	/**
	 * 改变工作目录
	 * @param path
	 * @throws IOException
	 */
	public void setWorkDirectory(String path) throws IOException {
		workDirectory = (config.getRootPath()+path);
		
		// 如果是手动控制可以设置改变工作目录
		if(handSwitch){
			client.changeWorkingDirectory(workDirectory);
		}
	}
	
	/**
	 * 创建目录
	 * @param pathname
	 * @return
	 * @throws IOException
	 */
	public boolean createDirectory(String pathname) throws IOException {
		if (!setReady()) {
			return false;
		}
		boolean okFlag = client.makeDirectory(pathname);
		setClose();
		return okFlag;
	}
	
	/**
	 *  获取当前工作目录
	 * @return
	 */
	public String getWorkDirectory() {
		return workDirectory;
	}
	
	/**
	 *  准备FTP连接环境
	 * @return
	 * @throws SocketException
	 * @throws IOException
	 */
	private boolean setReady() throws SocketException, IOException{
		if (!ready) {
			if (!ready()) {
				log.error("Ftp ready fail.");
				if(client.isConnected())
					client.disconnect();
				return false;
			}
		}
		ready = true;
		return true;
	}
	
	/**
	 *  设置是否ftp连接
	 * @throws IOException
	 */
	private void setClose() throws IOException{
		if(!handSwitch) close();
	}
	
	/**
	 *  打开手动连接
	 *
	 */
	public void openHandSwitch() {
		handSwitch = true;
	}
	
	/**
	 *  关闭手动连接
	 *
	 */
	public void closeHandSwitch() {
		handSwitch = false;
	}
}


二、读取配置文件类

/**
 * 
 *  FTP客户端的配置
 *
 * @author bleet (mailto:liuqiang2004456@163.com)
 */
public final class FtpClientConfig {
	
	/** ftp服务器地址 */
	private String server;
	
	/** ftp服务器端口 */
	private String port;
	
	/** ftp服务器用户名 */
	private String username;
	
	/** ftp服务器密码 */
	private String password;
	
	/** ftp服务器显示风格 一般为unix 或者nt*/
	private String FTPStyle;
	
	/** 本地编码格式 */
	private String localEncoding;
	
	/** 远程编码格式 */
	private String remoteEncoding;
	
	/** 是否设置 passiveMode模式 */
	private boolean passiveMode;
	
	/** 是否设置以二进制传输文件 */
	private boolean binaryFileType;
	
	/** ftp服务器工作根目录 */
	private String rootPath;
	
	/** 配置文件 */
	private String file;
	
	/** 单例 */
	private static  FtpClientConfig instance = null;
	
	private Logger log;
	
	/**
	 *  初始化参数
	 *
	 */
	private FtpClientConfig(String file) {
		try {
			log = Logger.getLogger(getClass());
			this.file = file;
			initConfig();
		} catch (Exception e) {
			log.error("FTP::读取配置文件错误.");
		}
	}
	
	/**
	 * 	获取配置实例
	 * @param file
	 * @return
	 */
	public static FtpClientConfig getInstance(String file) {
		if(null == instance)
			instance = new FtpClientConfig(file);
		return instance;
	}
	
	/**
	 *  读取配置文件
	 * @param prop
	 * @return
	 * @throws Exception
	 */
	private String getProperty(String prop) throws Exception {
		BufferedReader br = null;
		try {
			InputStream inStream = new FileInputStream(new File(file));
			br = new BufferedReader(new InputStreamReader(inStream));

			String temp = null;
			do{
				temp = br.readLine();
				if (temp == null)
					break;
				if (temp.startsWith("#"))
					continue;
				int index = temp.indexOf("=");
				if (index == -1)
					continue;
				String key = temp.substring(0, index).trim();
				String value = temp.substring(index + 1).trim();
				if (key.equals(prop)) {
					br.close();
					return value;
				}
			}while (temp != null);
			br.close();
			return null;
		} catch (Exception e) {
			if (br != null)
				br.close();
			throw e;
		}
	}
	
	/**
	 *  设置属性
	 * @throws Exception
	 */
	private void initConfig() throws Exception{
		setServer(getProperty("server"));
		setPort(getProperty("port"));
		setUsername(getProperty("username"));
		setPassword(getProperty("password"));
		setFTPStyle(getProperty("ftpstyle"));
		setLocalEncoding(getProperty("localencoding"));
		setRemoteEncoding(getProperty("remoteencoding"));
		setPassiveMode(getProperty("passivemode"));
		setBinaryFileType(getProperty("binaryfiletype"));
		setRootPath(getProperty("rootpath"));
	}
	
	/**
	 *  读取二进制传输方式设置
	 * @return
	 */
	public boolean getBinaryFileType() {
		return binaryFileType;
	}
	
	/**
	 *  默认以二进制形式传输文件
	 * @param binaryFileType
	 */
	public void setBinaryFileType(String binaryFileType) {
		if(null == binaryFileType){
			this.binaryFileType = true;
		}else {
			if("".equals(binaryFileType.trim())){
				this.binaryFileType = true;
			}else if ("true".equals(binaryFileType.trim())) {
				this.binaryFileType = true;
			}else if ("false".equals(binaryFileType.trim())) {
				this.binaryFileType = false;
			}
		}
	}

	public String getLocalEncoding() {
		return localEncoding;
	}
	
	/**
	 *  默认编码为UTF-8
	 */
	public void setLocalEncoding(String encoding) {
		if(null == encoding){
			localEncoding = "UTF-8";
		}else {
			if("".equals(encoding.trim())) localEncoding = "UTF-8";
		}
		this.localEncoding = encoding.trim();
	}

	public String getRemoteEncoding() {
		return remoteEncoding;
	}
	
	/**
	 *  默认编码为UTF-8
	 */
	public void setRemoteEncoding(String encoding) {
		if(null == encoding){
			this.remoteEncoding = "UTF-8";
		}else {
			if("".equals(encoding.trim())) remoteEncoding = "UTF-8";
		}
		this.remoteEncoding = encoding.trim();
	}
	
	public String getFTPStyle() {
		return FTPStyle;
	}
	
	/**
	 *  默认NT风格
	 * @param style
	 */
	public void setFTPStyle(String style) {
		if(null == style){
			this.FTPStyle = FTPClientConfig.SYST_NT;
		}else {
			if("".equals(style.trim())){
				this.FTPStyle = FTPClientConfig.SYST_NT;
			}else if ("unix".equals(style.trim())) {
				this.FTPStyle = FTPClientConfig.SYST_UNIX;
			}else if ("nt".equals(style.trim())) {
				this.FTPStyle = FTPClientConfig.SYST_NT;
			}
		}
	}

	public boolean getPassiveMode() {
		return passiveMode;
	}
	
	/**
	 * 默认支持passiveMode
	 * @param passiveMode
	 */
	public void setPassiveMode(String passiveMode) {
		if(passiveMode == null){
			this.passiveMode = true;
		}else {
			if("".equals(passiveMode.trim())){
				this.passiveMode = true;
			}else if ("true".equals(passiveMode.trim())) {
				this.passiveMode = true;
			}else if ("false".equals(passiveMode.trim())) {
				this.passiveMode = false;
			}
		}
	}

	public String getPassword() {
		return password;
	}

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

	public String getPort() {
		return port;
	}

	/**
	 *  默认端口为21
	 * @param port
	 */
	public void setPort(String port) {
		if( null == port ){
			port = "21";
		}else {
			if("".equals(port.trim())) port = "21";
		}
		this.port = port.trim();
	}

	public String getRootPath() {
		return rootPath;
	}
	
	/**
	 * 默认根目录为"/"
	 * @param rootPath
	 */
	public void setRootPath(String rootPath) {
		if( null == rootPath ){
			rootPath = "/";
		}else {
			if("".equals(rootPath.trim())) rootPath = "/";
		}
		this.rootPath = rootPath.trim();
	}

	public String getServer() {
		return server;
	}

	public void setServer(String server) {
		this.server = server;
	}

	public String getUsername() {
		return username;
	}

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


三、配置文件

server=10.1.1.1
port=21
username=username
password=password
ftpstyle=unix
localencoding=GBK
remoteencoding=GBK
passivemode=true
binaryfiletype=true
rootpath=/fileserver/ftp/


四、测试类  其中onconnet表示手动控制连接用法

public class Test {
	private static FtpClient client = FtpClient.getInstance("D:/ftpconf.properties");

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			//getFileList();
			//download("C:/", "startadmin.sh");
			//uoload();
			oneconnect();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void getFileList() throws IOException{
		String [] res = client.listFiles();
		for (int i = 0; i < res.length; i++) {
			System.out.println("---------------"+i+"--------------"+res[i]);
			
		}
	}
	
	public static void download(String path, String filename) throws IOException{
		client.download(path, filename);
	}

	/**
	 *  三个变量顺次为 本地路径 本地文件名 远端文件名
	 * @throws IOException
	 */
	public static void uoload() throws IOException{
		client.upload("C:/", "a.txt", "b.txt");
	}
	
	public static void oneconnect() throws IOException{
		client.openHandSwitch();
		if(!client.ready()){
			client.close();
		}else {
			getFileList();
			download("C:/", "startadmin.sh");
			uoload();
		}
		client.close();
		client.closeHandSwitch();
	}
	
}


代码贴完了,大家开始拍砖吧!
   发表时间:2009-08-08  
提提意见啊,一个个都是过路人~~~
0 请登录后投票
   发表时间:2009-08-10  
公司里我现在主要负责后台方面的开发任务。业务主要是电信行业里的一些报表查询及上报。故经常需要使用到 FTP把相关数据文件上传至指定服务器,所以对FTP的相关API有所了解。


简单看了一下代码,感觉需要改进。
0 请登录后投票
   发表时间:2009-08-10  
刚才不好意思,还没有写完,一不小心按错了键 就发送了,对不起了。

需要改进的地方,比如 不应该把 FTPClient类设计成单例类。
例如,对我们(像后台的程序)来说,大部分时候用多线程来并发进行
的,使用了单例方式就大大影响了 程序执行的速度。


仅属个人愚见,请高手们多多指教。
0 请登录后投票
   发表时间:2009-08-10  
liulyx 写道
大部分时候用多线程来并发进行
的,使用了单例方式就大大影响了 程序执行的速度。

不太明白,使用单例为什么会影响多线程执行的速度?我写成单例主要是为了去掉读配置文件的操作。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics