`
bleet
  • 浏览: 59002 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

阅读更多
每次在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();
	}
	
}


代码贴完了,大家开始拍砖吧!
分享到:
评论
6 楼 Reset 2011-12-15  
如果链接多个ftp服务器  这种方式的单态显然不是很合适
5 楼 Reset 2011-12-15  
liulyx 写道
刚才不好意思,还没有写完,一不小心按错了键 就发送了,对不起了。

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


仅属个人愚见,请高手们多多指教。


FTP服务器的有最大连接数,如果超过了最大连接数就会抛出异常,这里用FTPClient单态是很合适的,而且FTPClient是异步的,不会影响程序的执行速度。
4 楼 bleet 2009-08-10  
liulyx 写道
大部分时候用多线程来并发进行
的,使用了单例方式就大大影响了 程序执行的速度。

不太明白,使用单例为什么会影响多线程执行的速度?我写成单例主要是为了去掉读配置文件的操作。
3 楼 liulyx 2009-08-10  
刚才不好意思,还没有写完,一不小心按错了键 就发送了,对不起了。

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


仅属个人愚见,请高手们多多指教。
2 楼 liulyx 2009-08-10  
公司里我现在主要负责后台方面的开发任务。业务主要是电信行业里的一些报表查询及上报。故经常需要使用到 FTP把相关数据文件上传至指定服务器,所以对FTP的相关API有所了解。


简单看了一下代码,感觉需要改进。
1 楼 bleet 2009-08-08  
提提意见啊,一个个都是过路人~~~

相关推荐

    commons-net源码包

    1. **FTP协议实现**:Apache Commons Net包含了一个完整的FTP客户端库,支持主动和被动模式,断点续传,FTP上传和下载,以及FTP服务器的命令交互。源码中`org.apache.commons.net.ftp`包下的类,如`FTP`、`FTPClient...

    commons-ftp中ftpClient类的API--.doc

    FTPClient封装了所有必要的功能来存储和检索从FTP服务器上的文件。 这个类负责所有与FTP服务器交互的底层细节,并提供了便捷的更高层次的接口。 正如来自所有类SocketClient ,您必须首先连接到与服务器connect做...

    使用Apache commons-net.jar开发FTP工具类

    import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPReply; ``` 在`FtpUtils`类中,定义一个连接到FTP服务器的方法: ```java public class FtpUtils { public static ...

    JAVA实现ftp客户端的上传、下载、删除

    因此,通常我们会使用`org.apache.commons.net.ftp`库,这是一个由Apache Commons项目提供的FTP客户端库,它封装了FTP协议的许多细节,使开发更加简单。 1. **FTP连接**: 在开始任何操作之前,需要建立与FTP...

    Apache Common-net Ftp客户端实例

    import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPReply; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io....

    Java常用FTP文件操作说明Apache.FTPClient,ftp4j,jftp

    import org.apache.commons.net.ftp.FTPClient; public class JFtpExample { public static void main(String[] args) { FTPClient client = new FTPClient(); try { // 连接到FTP服务器 client.connect("ftp....

    javaFTPclient.rar_Ftp客户端__ftp_ftp客户端_ftp客户端 java_java ftp客户端

    Java的`org.apache.commons.net.ftp.FTPClient`库提供了这两种模式的支持。 4. **文件传输**:Java FTP客户端支持ASCII和二进制模式的文件传输。ASCII模式适用于文本文件,而二进制模式适用于所有其他类型的文件,...

    ftp客户端11.rar_JAVA访问 FTP_ftp客户端_ftp客户端 java_java ftp客户端_java 上传下载

    Java提供了一个内置的`java.net.Socket`类,可以用于实现FTP协议,但更常见的是使用`java.net.URL`和`java.net.URLConnection`类,或者使用Apache Commons Net库,该库提供了更完善的FTP客户端功能,包括文件上传、...

    基于java 的ftp客户端上传下载

    import org.apache.commons.net.ftp.FTPClient; FTPClient ftp = new FTPClient(); try { ftp.connect("ftp.example.com", 21); if (ftp.login("username", "password")) { ftp.setFileType(FTP.BINARY_FILE_...

    java 读取FTP服务器文件(二)

    import org.apache.commons.net.ftp.FTPClient; public class FtpReader { public static void main(String[] args) { FTPClient ftpClient = new FTPClient(); try { ftpClient.connect("ftp.server.com"); //...

    Java的FTP任务代码实例

    import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPReply; public class FtpUtil { private FTPClient ftpClient; private String hostname; private int port; ...

    FTP客户端源代码

    在Java中实现FTP客户端,通常会用到`java.net`和`java.io`这两个核心库,以及`org.apache.commons.net.ftp`库。Apache Commons Net是一个流行的Java库,提供了一系列FTP相关的类和方法,简化了FTP客户端的开发。例如...

    ftp上传下载

    import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; public class FtpUploader { public static void main(String[] args) { FTPClient ftpClient = new FTPClient(); try {...

    ftp客户端源码 java实现

    `org.apache.commons.net.ftp.FTPClient`是Apache Commons Net库提供的一个强大FTP客户端实现。它封装了FTP命令的发送和解析,提供了丰富的API,如`connect()`, `login()`, `binaryMode()`, `upload()`, `download...

    ORACLE中的FTP例子代码

    import org.apache.commons.net.ftp.FTPClient; public class FTPUploader { public static void uploadFile(String server, int port, String user, String password, String localFile, String remoteFile) { ...

    android 开源库上传FTP

    开源库的包名是这个org.apache.commons.net.ftp.FTPClient;是属于局域网的ftp上传,要有ip、端口、用户名以及密码。我根据网上的下载demo,自已研究了一番,又封装了一个类自已使用。欢迎访问博客:...

    gg.rar_GG132ftp_ftp_ftp java_gg.zip_java ftp

    在Java中实现FTP功能,通常会用到Java的`java.net`和`java.io`包,有时还会用到`org.apache.commons.net.ftp`库,这是一个Apache Commons项目提供的FTP客户端库,提供了更方便的API来处理FTP连接、上传、下载等操作...

    FTP使用心得

    包括FTP的客户端和服务器的安装包,commons-net-3.1 jar包,FTP的客户端服务器的详细安装和配置,和对org.apache.commons.net.ftp.FTPClient; 类的操作和封装的一些方法,和使用过程中遇到的一些问题的归纳,如...

    ftp帮助 java ftp

    import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPReply; ``` 为了简化配置,通常我们会创建一个属性文件(如`ftpconfig.properties`...

Global site tag (gtag.js) - Google Analytics