build.gradle
group 'com.aiuyo' version '1.0-SNAPSHOT' apply plugin: 'java' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { // https://mvnrepository.com/artifact/commons-net/commons-net compile group: 'commons-net', name: 'commons-net', version: '3.6' // https://mvnrepository.com/artifact/log4j/log4j compile group: 'log4j', name: 'log4j', version: '1.2.17' // https://mvnrepository.com/artifact/commons-io/commons-io compile group: 'commons-io', name: 'commons-io', version: '2.5' // https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.6' testCompile group: 'junit', name: 'junit', version: '4.12' }
FtpClientUtil
package com.aiuyo.util.ftpclientutil; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPReply; import org.apache.log4j.Logger; import java.io.*; import java.net.SocketException; import java.util.ArrayList; import java.util.List; /** * FtpClientUtil * 功能说明:FTP客户端 * @author WangXianfeng"wang-xianfeng@qq.com" 2017/7/21 16:25 **/ public class FtpClientUtil { private static final Logger logger = Logger.getLogger(FtpClientUtil.class); private static String encoding = "GBK"; private static FTPClient client; /** ftp服务器地址 */ private String host; /** ftp 端口号 默认21 */ private int port = 21; /** ftp服务器用户名 */ private String username; /** ftp服务器密码 */ private String password; /** ftp远程目录 */ private String remoteDir; /** 本地存储目录 */ private String localPath; /** 文件路径通配符 默认列出所有 */ private String regEx = "*"; /** 指定要下载的文件名 */ private String downloadFileName; /** * 功能说明:构造函数,默认21端口 * @param host FTP主机IP * @param username FTP用户名 * @param password FTP密码 * @return * @author WangXianfeng"wang-xianfeng@qq.com" */ public FtpClientUtil(String host, String username, String password){ this.host = host; this.username = username; this.password = password; } /** * 功能说明:构造函数,指定FTP端口 * @param host FTP主机IP * @param port FTP端口 * @param username FTP用户名 * @param password FTP密码 * @return * @author WangXianfeng"wang-xianfeng@qq.com" */ public FtpClientUtil(String host, int port, String username, String password){ this.host = host; this.port = port; this.username = username; this.password = password; } /** * 功能说明:连接FTP * @param * @return boolean * @author WangXianfeng"wang-xianfeng@qq.com" 2017/7/21 17:22 */ public boolean connectServer() { boolean connected = false; client = new FTPClient(); // 设置超时时间 client.setConnectTimeout(30000); try { //连接服务器 if (!client.isConnected()) { //连接FTP client.connect(host, port); // 登录 client.login(username, password); // 获取ftp登录应答码 int reply = client.getReplyCode(); // 验证是否登陆成功 if (!FTPReply.isPositiveCompletion(reply)) { logger.info("未连接到FTP,用户名或密码错误。"); client.disconnect(); } else { //设置连接属性 client.setControlEncoding(encoding); // 设置以二进制方式传输 client.setFileType(FTPClient.BINARY_FILE_TYPE); client.enterLocalPassiveMode(); logger.info("FTP连接成功。IP:" + host + ",PORT:" + port); connected = true; } } } catch (SocketException e) { try { client.disconnect(); } catch (IOException e1) { } logger.error("连接FTP服务器失败" + e.getMessage()); throw new RuntimeException("连接FTP服务器失败" + e.getMessage()); } catch (IOException e) { try { client.disconnect(); } catch (IOException e1) { } logger.error("连接FTP服务器失败" + e.getMessage()); throw new RuntimeException("连接FTP服务器失败" + e.getMessage()); } return connected; } /** * 功能说明:根据路径递归列返回文件列表 * @param remotePath 远程FTP路径 * @return java.util.List<java.lang.String> 文件列表 * @author WangXianfeng"wang-xianfeng@qq.com" 2017/7/21 17:31 */ public List<String> listAllFiles(String remotePath){ List<String> ftpFilePaths = new ArrayList<>(); //是否连接服务器标识 boolean isConnected = false; //如果未连接服务器,则调用connectServer方法连接 if(null==this.client||!this.client.isConnected()){ isConnected = this.connectServer(); }else{ isConnected = this.client.isConnected(); } //如果已经连接,则列出文件 if(isConnected){ //递归获取远程FTP上的所有文件路径 try { logger.info("Listing directory:" + remotePath); if(remotePath.endsWith("/")){ remotePath = remotePath.substring(0,remotePath.length() - 1); } FTPFile[] files = this.client.listFiles(remotePath); for (FTPFile file:files) { if (file.isFile()) { ftpFilePaths.add(remotePath + "/" + file.getName()); } else if (file.isDirectory()) { //如果是目录,递归调用该方法返回该目录下的文件 List<String> subList = listAllFiles( remotePath + "/" + file.getName()); ftpFilePaths.addAll(subList); } } } catch (IOException e) { logger.error("发生IO异常",e); } } logger.info("List ftp file done"); return ftpFilePaths; } /** * 功能说明:下载单个FTP文件到本地 * @param localPath 本地文件路径 * @param localFileName 本地文件名称,留空则与远程文件保持一致 * @param remotePath FTP路径 * @param remoteFileName FTP文件名称 * @return boolean * @author WangXianfeng"wang-xianfeng@qq.com" 2017/7/21 17:54 */ public boolean downloadFile(String localPath,String localFileName,String remotePath,String remoteFileName)throws Exception{ boolean successFlag = false; //是否连接服务器标识 boolean isConnected = false; //如果未连接服务器,则调用connectServer方法连接 if(null==this.client||!this.client.isConnected()){ isConnected = this.connectServer(); }else{ isConnected = this.client.isConnected(); } if(isConnected){ File downloadFile = null; try { //检查输入参数 checkParams("download",localPath,localFileName,remotePath,remoteFileName); //设置远程FTP目录 if(StringUtils.isEmpty(remotePath)){ remotePath = this.remoteDir; } if(remotePath.endsWith("/")){ remotePath = remotePath.substring(0,remotePath.length() - 1); } client.changeWorkingDirectory(remotePath); logger.info("切换至工作目录【" + remotePath + "】成功"); //读取远程文件 FTPFile[] ftpFiles = client.listFiles(); if (ftpFiles.length == 0) { logger.warn("文件数为0,没有可下载的文件!"); successFlag = false; } logger.info("准备下载" + ftpFiles.length + "个文件"); // 3、保存文件到本地 for (FTPFile file : ftpFiles) { if(file.isFile()) { logger.debug("正在保存文件:" + remotePath + "/" + file.getName() + "至本地"); //指定下载的文件 if (StringUtils.isNotBlank(remoteFileName) && !file.getName().equals(remoteFileName)) { continue; } if(StringUtils.isEmpty(localPath)){ localPath = this.getLocalPath(); } if(StringUtils.isEmpty(localFileName)){ localPath = localPath + File.separator + file.getName(); }else{ localPath = localPath + File.separator + localFileName; } downloadFile = new File(localPath); OutputStream os = new FileOutputStream(downloadFile); client.retrieveFile(file.getName(), os); IOUtils.closeQuietly(os); logger.info("文件下载成功,文件路径:" + localPath); successFlag = true; } } } catch (Exception e) { logger.error("下载文件失败" + e.getMessage()); throw new RuntimeException("下载文件失败" + e.getMessage()); } } return successFlag; } /** * 功能说明:检查下载文件的输入参数是否合法 * @param localPath * @param localFileName * @param remotePath * @param remoteFileName * @return void * @throws Exception * @author WangXianfeng"wang-xianfeng@qq.com" 2017-07-22 06:33:44 */ private void checkParams(String operType,String localPath, String localFileName, String remotePath, String remoteFileName) throws Exception{ if(StringUtils.isEmpty(this.localPath)&&StringUtils.isEmpty(localPath)){ throw new Exception("未指定本地目录"); } if(StringUtils.isEmpty(this.remoteDir)&&StringUtils.isEmpty(remotePath)){ throw new Exception("未指定FTP远程目录"); } if(!StringUtils.isEmpty(operType)&&"download".equals(operType)){ if(StringUtils.isEmpty(remoteFileName)){ throw new Exception("未指定下载文件名"); } } if(!StringUtils.isEmpty(operType)&&"upload".equals(operType)){ if(StringUtils.isEmpty(localFileName)){ throw new Exception("未指定本地上传文件名"); } } } /** * 功能说明:上传本地单个文件到远程目录 * @param localPath * @param localFileName * @param remotePath * @param remoteFileName * @return boolean * @throws * @author WangXianfeng"wang-xianfeng@qq.com" 2017-07-22 07:17:45 */ public boolean uploadFile(String localPath,String localFileName,String remotePath,String remoteFileName)throws Exception{ boolean successFlag = false; //是否连接服务器标识 boolean isConnected = false; //如果未连接服务器,则调用connectServer方法连接 if(null==this.client||!this.client.isConnected()){ isConnected = this.connectServer(); }else{ isConnected = this.client.isConnected(); } if(isConnected){ //检查输入参数 checkParams("upload",localPath,localFileName,remotePath,remoteFileName); //设置远程FTP目录 if(StringUtils.isEmpty(remotePath)){ remotePath = this.remoteDir; } if(remotePath.endsWith("/")){ remotePath = remotePath.substring(0,remotePath.length() - 1); } client.changeWorkingDirectory(remotePath); logger.info("切换至工作目录【" + remotePath + "】成功"); try { //准备本地需要上传的文件 if(StringUtils.isEmpty(localPath)){ localPath = this.getLocalPath(); } localPath = localPath + File.separator + localFileName; File localFile = new File(localPath); OutputStream os = null; os = client.storeFileStream(localFile.getName()); if (os == null){ throw new RuntimeException("上传失败,请检查是否有上传权限"); } IOUtils.copy(new FileInputStream(localFile), os); IOUtils.closeQuietly(os); logger.info("文件上传成功,上传文件路径:" + remotePath + "/" + localFile.getName()); }catch (Exception e){ logger.error("上传文件失败" + e.getMessage()); throw new RuntimeException("上传文件失败" + e.getMessage()); } } return successFlag; } /** * 功能说明:下载远程目录所有的文件到本地目录 * @param localPath * @param remotePath * @return java.util.List<java.lang.String> 本地文件列表 * @throws * @author WangXianfeng"wang-xianfeng@qq.com" 2017-07-22 08:10:40 */ public List<String> downloadDirectory(String localPath,String remotePath)throws Exception { List<String> localFilePathList = new ArrayList<>(); //是否连接服务器标识 boolean isConnected = false; //如果未连接服务器,则调用connectServer方法连接 if (null == this.client || !this.client.isConnected()) { isConnected = this.connectServer(); } else { isConnected = this.client.isConnected(); } if (isConnected) { try { logger.info("正在下载远程目录:" + remotePath + "到本地目录:" + localPath); //检查输入参数 if(StringUtils.isEmpty(this.localPath)&&StringUtils.isEmpty(localPath)){ throw new Exception("未指定本地目录"); } if(StringUtils.isEmpty(this.remoteDir)&&StringUtils.isEmpty(remotePath)){ throw new Exception("未指定FTP远程目录"); } //设置远程FTP目录 if (StringUtils.isEmpty(remotePath)) { remotePath = this.remoteDir; } if (remotePath.endsWith("/")) { remotePath = remotePath.substring(0, remotePath.length() - 1); } client.changeWorkingDirectory(remotePath); logger.info("切换至工作目录【" + remotePath + "】成功"); //读取远程文件 FTPFile[] ftpFiles = client.listFiles(); if (ftpFiles.length == 0) { logger.warn("文件数为0,没有可下载的文件!"); return localFilePathList; } logger.info("准备下载" + ftpFiles.length + "个文件"); String localFilePath = null; //保存文件到本地 for (FTPFile file : ftpFiles) { if (file.isFile()) { logger.debug("正在保存文件:" + remotePath + "/" + file.getName() + "至本地"); if (StringUtils.isEmpty(localPath)) { localPath = this.getLocalPath(); } File localDir = new File(localPath); if(!localDir.exists()){ localDir.mkdir(); } localFilePath = localPath + File.separator + file.getName(); File downloadFile = new File(localFilePath); OutputStream os = new FileOutputStream(downloadFile); client.retrieveFile(file.getName(), os); IOUtils.closeQuietly(os); logger.info("文件下载成功,文件路径:" + localFilePath); localFilePathList.add(localPath); }else if(file.isDirectory()){ localPath += File.separator + file.getName(); remotePath += "/" + file.getName(); List<String> subDirPathList = this.downloadDirectory(localPath,remotePath); localFilePathList.addAll(subDirPathList); } } } catch (Exception e) { logger.error("下载文件失败" + e.getMessage()); throw new RuntimeException("下载文件失败" + e.getMessage()); } } return localFilePathList; } /** * 功能说明:关闭FTP连接 * @param * @return void * @throws * @author WangXianfeng"wang-xianfeng@qq.com" 2017-07-22 08:09:23 */ public void closeConnect() { try { client.disconnect(); logger.info(" 关闭FTP连接成功!!! "); } catch (IOException e) { logger.warn(" 关闭FTP连接失败!!! ", e); } } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } 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 getRemoteDir() { return remoteDir; } public void setRemoteDir(String remoteDir) { this.remoteDir = remoteDir; } public String getLocalPath() { return localPath; } public void setLocalPath(String localPath) { this.localPath = localPath; } public String getRegEx() { return regEx; } public void setRegEx(String regEx) { this.regEx = regEx; } public String getDownloadFileName() { return downloadFileName; } public void setDownloadFileName(String downloadFileName) { this.downloadFileName = downloadFileName; } }
文章评论