Appache Ftp使用(二)
一:前言
之前已经介绍过Appache Ftp的简单配置和封装,本篇文章将直接进行多个方法功能的封装和组合使用。
二:编写ftp方法实用方法
- 单个文件下载
/** * 方法 downloadFile * * @param localFilePath 本地存放下载文件的路径 * @param fileName ftp上的待下载的文件名 * @param ftpFilePath ftp远程文件路径 * @return */ public boolean downloadFile(String localFilePath, String fileName, String ftpFilePath) { boolean result = false; String message = ""; OutputStream is = null; if (ftpClient != null) { log.info("正在下载文件:" + fileName + ",请等待..."); // ftp登陆目录下的目录路径 try { // 1,创建本地文件下载路径 File localFile = new File(localFilePath); if (!localFile.exists()) { localFile.mkdirs(); } // 2,判断文件是否已经存在,如果存在,则先删除该文件 File fi = new File(localFilePath + fileName); if (fi.exists()) { fi.delete(); } // 3,转移到FTP服务器目录至指定的目录下 ftpClient.changeWorkingDirectory(new String(ftpFilePath.getBytes(encoding), "iso-8859-1")); // 获取文件列表 boolean isFileExist = false; FTPFile[] fs = ftpClient.listFiles(); for (FTPFile ff : fs) { if (ff.getName().equals(fileName)) { File localFile1 = new File(localFilePath + "/" + fileName); is = new FileOutputStream(localFile1); ftpClient.retrieveFile(ff.getName(), is); isFileExist = true; break; } } if (!isFileExist) { log.error("文件" + fileName + "不存在"); return result; } message = "下载文件: " + fileName + " 到目录: " + localFilePath + " 成功!"; log.info(message); result = true; } catch (IOException e) { message = "下载文件: " + fileName + " 到目录: " + localFilePath + " 失败!"; log.info(message); result = false; } finally { try { if (is != null) { is.close(); } } catch (IOException e) { throw new RuntimeException("下载ftp文件OutputStream关闭失败!", e); } if (ftpClient.isConnected()) { try { ftpClient.disconnect(); } catch (IOException e) { throw new RuntimeException("与ftp主机断开连接失败!", e); } } } } else { result = false; } return result; }
- 多个文件下载
/** * 方法 downloadFiles * * @param localFilePath 本地存放下载文件的路径 * @param files ftp上的待下载的文件名称列表 * @param ftpFilePath 远程文件路径 * @return */ public boolean downloadFiles(String localFilePath, String[] files, String ftpFilePath) { boolean result = false; String message = ""; OutputStream is = null; String fileName = null; if (ftpClient != null) { try { // 转移到FTP服务器目录至指定的目录下 ftpClient.changeWorkingDirectory(new String(ftpFilePath.getBytes(encoding), "iso-8859-1")); for (String str : files) { fileName = str; log.info("正在下载文件:" + fileName + ",请等待..."); // 1,创建本地文件下载路径 File localFile = new File(localFilePath); if (!localFile.exists()) { localFile.mkdirs(); } // 2,判断文件是否已经存在,如果存在,则先删除该文件 File fi = new File(localFilePath + fileName); if (fi.exists()) { fi.delete(); } boolean isFileExist = false; // 获取文件列表 FTPFile[] fs = ftpClient.listFiles(); for (FTPFile ff : fs) { if (ff.getName().equals(fileName)) { File localFile1 = new File(localFilePath + "/" + fileName); is = new FileOutputStream(localFile1); ftpClient.retrieveFile(ff.getName(), is); isFileExist = true; break; } } if (!isFileExist) { log.error("文件" + fileName + "不存在"); return result; } message = "下载文件: " + fileName + " 到目录: " + localFilePath + " 成功!"; log.info(message); } result = true; } catch (IOException e) { message = "下载文件: " + fileName + " 到目录: " + localFilePath + " 失败!"; log.error(message); result = false; } finally { try { if (is != null) { is.close(); } } catch (IOException e) { throw new RuntimeException("下载ftp文件OutputStream关闭失败!", e); } if (ftpClient.isConnected()) { try { ftpClient.disconnect(); } catch (IOException e) { throw new RuntimeException("与ftp主机断开连接失败!", e); } } } } return result; }
- 单个文件上传(IO流形式)
/** * 方法 uploadFile * * @param is 上传文件流 * @param fileName ftp上的待上传的文件名 * @param ftpFilePath 远程文件路径 * @return */ public boolean uploadFile(InputStream is, String fileName, String ftpFilePath) { boolean result = false; String message = ""; if (ftpClient != null) { log.info("正在上传文件:" + fileName + ",请等待..."); try { // 转移工作目录至指定目录下 boolean change = ftpClient.changeWorkingDirectory(ftpFilePath); if (!change) { // 文件路径不存在 this.makeDirectorys(ftpFilePath); } result = ftpClient.storeFile(new String(fileName.getBytes(encoding), "iso-8859-1"), is); if (!result) { log.error("上传文件失败!"); return false; } message = "上传文件: " + fileName + " 到目录: " + ftpFilePath + " 成功!"; log.info(message); result = true; } catch (IOException e) { message = "上传文件: " + fileName + " 到目录: " + ftpFilePath + " 失败!"; log.error(message, e); result = false; } finally { try { if (is != null) { is.close(); } } catch (IOException e) { throw new RuntimeException("上传ftp文件InputStream关闭失败!", e); } } } return result; }
- 获取单个文件文件流
/** * 方法 getFileInputStream 获取文件流 * * @param fileName ftp上的待下载的文件名 * @param ftpFilePath ftp远程文件路径 * @return */ public InputStream getFileInputStream(String ftpFilePath,String fileName) { boolean result = false; InputStream is = null; try { result = ftpClient.changeWorkingDirectory(new String(ftpFilePath.getBytes(encoding), "iso-8859-1")); if (!result) { logger.error("切换路径到:"+ftpFilePath+"失败,请检查路径是否存在!"); return null; } is = ftpClient.retrieveFileStream(fileName); return is; } catch (IOException e) { throw new RuntimeException("从文件路径"+ftpFilePath+"读取文件: " + fileName + "失败!", e); }finally { try { //获取流成功情况下,手动告诉ftp,io流处理完成 if(is != null){ ftpClient.completePendingCommand(); } } catch (IOException e) { throw new RuntimeException("执行ftpClient.completePendingCommand()失败", e); } } }
- 复制文件到ftp新路径
/** * 复制文件. * * @param fileName 文件名称 * @param sourceFtpFilePath 源文件存放位置 * @param targetFtpFilePath 目标位置 */ public boolean copyFile(String fileName, String sourceFtpFilePath, String targetFtpFilePath) { ByteArrayInputStream in = null; ByteArrayOutputStream fos = new ByteArrayOutputStream(); boolean result =false; logger.info("从原路径"+sourceFtpFilePath+ "复制文件"+fileName+"到"+targetFtpFilePath+"开始"); try { // 转移工作目录至指定目录下 boolean change = ftpClient.changeWorkingDirectory(sourceFtpFilePath); if (!change) { // 文件路径不存在 logger.error("原文件存放路径" + sourceFtpFilePath + "不存在"); return result; } // 获取文件列表 boolean isFileExist = false; FTPFile[] fs = ftpClient.listFiles(); for (FTPFile ff : fs) { if (ff.getName().equals(fileName)) { ftpClient.retrieveFile(ff.getName(), fos); isFileExist = true; break; } } if (!isFileExist) { logger.error("文件" + fileName + "不存在"); return result; } in = new ByteArrayInputStream(fos.toByteArray()); // 返回根路径 returnRootDirectory(); // 切换到目标路径存放文件 change = ftpClient.changeWorkingDirectory(targetFtpFilePath); if (!change) { // 文件路径不存在创建路径 this.makeDirectorys(targetFtpFilePath); } ftpClient.storeFile(new String(fileName.getBytes(encoding), "iso-8859-1"), in); logger.info("从原路径"+sourceFtpFilePath+ "复制文件"+fileName+"到"+targetFtpFilePath+"成功"); return true; }catch(Exception e){ throw new RuntimeException("从原路径"+sourceFtpFilePath+ "复制文件"+fileName+"到"+targetFtpFilePath+"失败。失败原因为:", e); }finally { try { if (in != null) { in.close(); } } catch (IOException e) { throw new RuntimeException("复制ftp文件ByteArrayInputStream关闭失败!", e); } try { if (fos != null) { fos.close(); } } catch (IOException e) { throw new RuntimeException("复制ftp文件ByteArrayOutputStream关闭失败!", e); } } }
- 递归创建路径(如/XXX/XXX/XXX)
/** * 递归创建远程服务器目录 * * @param ftpFilePath 远程服务器文件绝对路径 * @return 目录创建是否成功 */ public boolean makeDirectorys(String ftpFilePath) { boolean result = true; String directory = ftpFilePath.substring(0, ftpFilePath.lastIndexOf("/") + 1); try { if (!directory.equalsIgnoreCase("/") && !ftpClient.changeWorkingDirectory(new String(directory.getBytes(encoding), "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(ftpFilePath.substring(start, end).getBytes(encoding), "iso-8859-1"); if (!ftpClient.changeWorkingDirectory(subDirectory)) { if (ftpClient.makeDirectory(subDirectory)) { ftpClient.changeWorkingDirectory(subDirectory); } else { logger.error("创建目录失败"); return false; } } start = end + 1; end = directory.indexOf("/", start); // 检查所有目录是否创建完毕 if (end <= start) { break; } } } else { logger.info("文件夹已经存在,不需要重新创建"); } } catch (Exception e) { throw new RuntimeException( "创建文件夹过程出错", e); } return result; }
- 获取ftp路径下文件列表
本功能需要使用vo辅助实现/** * 获取文件列表(按时间倒序输出) * * @param ftpFilePath 远程文件路径 * @return */ public List<FtpFileVo> getFtpFiles(String ftpFilePath) { List<FtpFileVo> list = new ArrayList<FtpFileVo>(); try { // 转移到FTP服务器目录至指定的目录下 boolean result = ftpClient.changeWorkingDirectory(new String(ftpFilePath.getBytes(encoding), "iso-8859-1")); if (!result) { log.error("切换路径到:"+ftpFilePath+"失败,请检查路径是否存在!"); return list; } log.info("正在获取文件夹:" + ftpFilePath + "下文件列表,请等待..."); FTPFile[] fs = ftpClient.listFiles(); for (FTPFile ff : fs) { // 如果不是文件的类型,跳过 if (!ff.getRawListing().startsWith("-")) { continue; } FtpFileVo vo = new FtpFileVo(); vo.setFileName(ff.getName()); vo.setLastModifyDate(ff.getTimestamp().getTime()); vo.setSize(ff.getSize() / 1024); vo.setFilePath(ftpFilePath); list.add(vo); } // 按照时间倒序排序 Collections.sort(list); log.info("获取文件路径下文件列表成功"); return list; } catch (IOException e) { throw new RuntimeException( "获取文件列表过程出错", e); } }
import java.util.Date; public class FtpFileVo implements Comparable<FtpFileVo> { private Date LastModifyDate; // 单位为kb private long size; private String fileName; private String filePath; public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } public Date getLastModifyDate() { return LastModifyDate; } public void setLastModifyDate(Date lastModifyDate) { LastModifyDate = lastModifyDate; } public long getSize() { return size; } public void setSize(long size) { this.size = size; } public int compareTo(FtpFileVo stu) { return stu.getLastModifyDate().compareTo(this.LastModifyDate); } }
三:其他说明
- Appache FTP下文件上传会是覆盖操作,所以上传前一定要考虑好是否备份
- Appache FTP获取IO流方法,必须在Finally方法中执行以下方法,因为ftp不会自动放开本次流的操作,其余操作无法正常进行
ftpClient.completePendingCommand();
四:结束
本文主要是进行FTP常用方法罗列,其中涉及到的方法中有部分已经在finally中进行连接断开,这部分内容可以根据实际需要进行,如多个操作在同一个流程中,就没有必要每次都连接,之后断开又连接,可以一次操作结束后再断开连接。