FTP实用类

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 java.util.ResourceBundle;

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.FTPFileFilter;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;

/**
 * 支持断点续传的FTP实用类
 * 
 * @version 0.1 实现基本断点上传下载
 * @version 0.2 实现上传下载进度汇报
 * @version 0.3 实现中文目录创建及中文文件创建,添加对于中文的支持
 */
public class FTPEngine {
	private static Logger log = Logger.getLogger(FTPEngine.class);

	// 枚举类UploadStatus代码
	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代码
	public enum DownloadStatus {
		Remote_File_Noexist, // 远程文件不存在
		Local_Bigger_Remote, // 本地文件大于远程文件
		Download_From_Break_Success, // 断点下载文件成功
		Download_From_Break_Failed, // 断点下载文件失败
		Download_New_Success, // 全新下载文件成功
		Download_New_Failed; // 全新下载文件失败
	}

	public FTPClient ftpClient = new FTPClient();
	private String host;
	private int port;
	private String username;
	private String password;

	// private String localFilePath;
	// private String remoteFilePath;

	public FTPEngine(String host, int port, String username, String password) {
		// 设置将过程中使用到的命令输出到控制台
		this.host = host;
		this.port = port;
		this.username = username;
		this.password = password;
		this.ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
	}

	public FTPEngine() {
		//从ftp.properties中读取连接ftp的参数
		ResourceBundle bundle = ResourceBundle.getBundle("ftp");
		this.host = bundle.getString("host");
		try {
			this.port = Integer.parseInt(bundle.getString("port"));
		} catch (Exception e) {
			this.port = 21;
		}
		this.username = bundle.getString("username");
		this.password = bundle.getString("password");
	}
	/** */
	/**
	 * 连接到FTP服务器
	 * 
	 * @param hostname
	 *            主机名
	 * @param port
	 *            端口
	 * @param username
	 *            用户名
	 * @param password
	 *            密码
	 * @return 是否连接成功
	 * @throws IOException
	 */
	public boolean connect() throws IOException {
		ftpClient.connect(host, 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("UTF-8"), "iso-8859-1"));
		if (files.length < 1) {
			log.error("远程文件不存在");
			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) {
				log.error("本地文件大于远程文件,下载中止");
				return DownloadStatus.Local_Bigger_Remote;
			}

			// 进行断点续传,并记录状态
			FileOutputStream out = new FileOutputStream(f, true);
			ftpClient.setRestartOffset(localSize);
			InputStream in = ftpClient.retrieveFileStream(new String(remote.getBytes("UTF-8"), "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) {
						log.info("下载进度:" + process + "%");
					}
					// 更新文件下载进度,值存放在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("UTF-8"), "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) {
						log.info("下载进度:" + process + "%");
					}
					// 更新文件下载进度,值存放在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服务器上下载文件
	 * 取得目标路径以filterStartWith开头的文件
	 * 
	 * @param remote
	 *            远程文件路径
	 * @param local
	 *            本地文件路径
	 * @param filter
	 *            过滤字符串
	 * @return 上传的状态
	 * @throws IOException
	 */
	public DownloadStatus download(String remote, String local, final String filterStartWith) throws IOException {
		// 设置被动模式
		ftpClient.enterLocalPassiveMode();
		// 设置以二进制方式传输
		ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
		DownloadStatus result;

		// 检查远程文件是否存在
		FTPFile[] files = ftpClient.listFiles(new String(remote.getBytes("UTF-8"), "iso-8859-1"),
				new FTPFileFilter(){
					@Override
					public boolean accept(FTPFile file) {
						String fileName = file.getName();
						return fileName.toUpperCase().startsWith(filterStartWith);
					}
			
		});
		if (files.length < 1) {
			log.error("远程文件不存在");
			return DownloadStatus.Remote_File_Noexist;
		}

		long lRemoteSize = files[0].getSize();
		File f = new File(local);

		OutputStream out = new FileOutputStream(f);
		InputStream in = ftpClient.retrieveFileStream(new String(remote
				.getBytes("UTF-8"), "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) {
					log.info("下载进度:" + process + "%");
				}
				// 更新文件下载进度,值存放在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或是
	 *            http://IP:PORT/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("UTF-8");
		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("UTF-8"), "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;
				}*/
				ftpClient.deleteFile(remoteFileName);
				result = uploadFile(remoteFileName, new File(local), ftpClient, 0);
			//}
		} else {
			result = uploadFile(remoteFileName, new File(local), ftpClient, 0);
		}
		return result;
	}

	/**
	 * 删除FTP服务器的文件
	 * 
	 * @param remotePath
	 * @param remoteFile
	 * @return
	 */
	public boolean delete(String remotePath, String remoteFile) {
		boolean status = false;
		try {
			boolean flag = ftpClient.deleteFile(remotePath + remoteFile);
			if (flag)
				if (ftpClient.getReplyCode() == 250)
					status = true;
		} catch (IOException e) {
			log.error("删除文件 " + remotePath + remoteFile + " 失败!!!");
			e.printStackTrace();
		}
		return status;
	}
	
	public boolean doRename(String from, String to){
		boolean status = false;
		try{
			//ftpClient.cwd();
			status = ftpClient.rename(from, to);
		}catch (Exception e) {
			log.error("Rename failed.");
			e.printStackTrace();
		}
		return status;
	}

	/** */
	/**
	 * 断开与远程服务器的连接
	 * 
	 * @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("UTF-8"), "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("UTF-8"), "iso-8859-1");
				if (!ftpClient.changeWorkingDirectory(subDirectory)) {
					if (ftpClient.makeDirectory(subDirectory)) {
						ftpClient.changeWorkingDirectory(subDirectory);
					} else {
						log.error("创建目录失败");
						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();
		double process = 0;
		long localreadbytes = 0L;
		RandomAccessFile raf = new RandomAccessFile(localFile, "r");
		OutputStream out = ftpClient.appendFileStream(new String(remoteFile.getBytes("UTF-8"), "UTF-8"));
		// 断点续传
		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;
				log.info("上传进度:" + process * 100 + "%");
				// 汇报上传状态
			}
		}
		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;
	}

	/**
	 * 判断指定文件名的文件是否存在<br>
	 * 返回匹配到的文件个数
	 * 
	 * @param fileName
	 * @return
	 */
	public int doExistsFile(String fileName) {
		try {
			FTPFile[] file = ftpClient.listFiles(fileName);
			return file.length;
		} catch (IOException e) {
			e.printStackTrace();
			return 0;
		}
	}
	
	/**
	 * 获取远程服务器指定路径下的以固定字符串开头的文件名
	 * @param remote  远程路径
	 * @param filterStartWith  过滤字段-以本字段开头
	 * @return
	 * @throws IOException
	 */
	public FTPFile[] readRemoteFilesName(String remote, final String filterStartWith) throws IOException {
		// 检查远程文件是否存在
		FTPFile[] files = ftpClient.listFiles(new String(remote.getBytes("UTF-8"), "iso-8859-1"),
				new FTPFileFilter(){
					@Override
					public boolean accept(FTPFile file) {
						String fileName = file.getName();
						return fileName.toUpperCase().startsWith(filterStartWith);
					}
		});
		return files;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值