package com.primeton.damp.fileclient; import org.apache.commons.lang.StringUtils; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPReply; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Properties; import java.util.stream.Collectors; /** * Created by zhaopx on 2018/8/9. */ public class FtpClientHandler implements X11ClientHandler { protected static Logger logger = LoggerFactory.getLogger("FtpClientHandler"); private FTPClient ftpClient; private int reply; private final String ftpHost; private final int ftpPort; private final String ftpUsername; private final String ftpPassword; public FtpClientHandler(String host, int port, String username, String password, Properties params) { ftpHost = host; ftpPort = port; ftpUsername = username; ftpPassword = password; this.reconnect(params); } /** * 以账号和密码重新连接 * @param params */ public void reconnect(Properties params) { try { ftpClient = new FTPClient(); ftpClient.connect(ftpHost, ftpPort); //连接Ftp服务器 ftpClient.login(ftpUsername, ftpPassword); ftpClient.setControlEncoding("UTF-8"); ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); ftpClient.enterLocalPassiveMode(); // 被动模式 reply = ftpClient.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { logger.info("Donot connect FTP Server, username or password is error."); ftpClient.disconnect(); } else { logger.info("The FTP connect success."); } } catch (IOException e) { logger.error("ftp connect is error.", e); throw new IllegalStateException("can not connect sftp: " + ftpHost+":"+ ftpPort); } } /** * 读取文件流 * @param file * @return * @throws IOException */ @Override public InputStream readFile(String file) throws IOException { return ftpClient.retrieveFileStream(file); } /** * 读取文件流 * @param file * @return * @throws IOException */ @Override public OutputStream writeFile(String file, boolean overwrite) throws IOException { if(overwrite) { return ftpClient.storeFileStream(file); } else { return ftpClient.appendFileStream(file); } } @Override public boolean rename(String file, String newFileName) { try { final Path path1 = Paths.get(file); Path fileP = path1.getParent(); if(fileP == null) { fileP = Paths.get("/"); } return ftpClient.rename(file, Paths.get(fileP.toString(), newFileName).toString()); } catch (IOException e) { logger.error("Error in rename ftp file.", e); return false; } } /** * 删除文件, 返回 true 则删除成功 * @param fileName */ @Override public boolean deleteFile(String fileName) { if("/".equals(fileName)) { return false; } final Path path1 = Paths.get(fileName); Path fileP = path1.getParent(); if(fileP == null) { fileP = Paths.get("/"); } try { final FTPFile[] ftpFiles = ftpClient.listFiles(fileP.toString()); for (FTPFile ftpFile : ftpFiles) { if (StringUtils.equals(path1.getFileName().toString(), ftpFile.getName())) { deleteFile(fileP.toString(), ftpFile); return true; } } } catch (IOException e) { throw new RuntimeException(e); } return false; } /** * 递归删除文件和文件夹 * @param file */ private void deleteFile(String basePath, FTPFile file) throws IOException { String prefixPath = basePath.endsWith("/") ? basePath : basePath + "/"; if(file.isDirectory()) { FTPFile[] ftpFiles = ftpClient.listFiles(file.getName()); for (FTPFile ftpFile : ftpFiles) { deleteFile(prefixPath + file.getName(), ftpFile); } ftpClient.removeDirectory(prefixPath + file.getName()); } else { ftpClient.deleteFile(prefixPath + file.getName()); } } /** * 判断目录是否存在 * @param path * @return */ @Override public boolean existsDir(String path) { if("/".equals(path)) { return true; } try { final Path path1 = Paths.get(path); Path fileP = path1.getParent(); if(fileP == null) { fileP = Paths.get("/"); } final FTPFile[] ftpFiles = ftpClient.listFiles(fileP.toString()); for (FTPFile ftpFile : ftpFiles) { if(StringUtils.equals(path1.getFileName().toString(), ftpFile.getName())) { return ftpFile.isDirectory(); } } } catch (IOException e) { logger.error(e.getMessage()); } return false; } /** * 判断目录是否存在 * @param path * @return */ @Override public boolean existsFile(String path) { if("/".equals(path)) { return false; } try { final Path path1 = Paths.get(path); Path fileP = path1.getParent(); if(fileP == null) { fileP = Paths.get("/"); } final FTPFile[] ftpFiles = ftpClient.listFiles(fileP.toString()); for (FTPFile ftpFile : ftpFiles) { if(StringUtils.equals(path1.getFileName().toString(), ftpFile.getName())) { return ftpFile.isFile(); } } } catch (IOException e) { logger.error(e.getMessage()); } return false; } /** * 判断目录或者文件是否存在 * @param path * @return */ @Override public boolean exists(String path) { try { final FTPFile ftpFile = ftpClient.mdtmFile(path); return ftpFile != null && ftpFile.isValid(); } catch (IOException e) { logger.error(e.getMessage()); } return false; } /** * 创建多层目录 * @param path * @return */ @Override public boolean mkdirs(String path) { Path path1 = Paths.get(path); Path parentPath = path1.getParent(); if(existsDir(parentPath.toString())){ return mkdir(path1.toString()); // 创建当前文件夹 } else { if("/".equals(parentPath.toString()) || mkdirs(parentPath.toString())) { // 创建父级目录 return mkdir(path1.toString()); // 创建当前文件夹 } } // 最后创建文件夹肯定是不成功的。 return existsDir(path); } /** * 创建目录, 返回 true 则创建目录成功 * @param dirName 一级或者多级目录 */ @Override public boolean mkdir(String dirName) { try { return ftpClient.makeDirectory(dirName); } catch (IOException e) { throw new RuntimeException("mkdir " + dirName + " fail.", e); } } /** * 获取一个目录下或者文件的子文件 * @param ftpPath * @return */ @Override public List getChildren(String ftpPath) { try { FTPFile[] ftpFiles = ftpClient.listFiles(ftpPath); List files = Arrays.stream(ftpFiles).map(it->Paths.get(ftpPath, it.getName())).collect(Collectors.toList()); return files; } catch (IOException e) { logger.info("Error in scan ftpfile."); } return Collections.emptyList(); } @Override public void close() throws IOException { ftpClient.disconnect(); } }