很多时候我们会遇到从FTP上上传和下载文件,但是FTP分为了三种主要实现,分别是FTP,FTPS,SFTP。我们封装一个一套工具类来实现它的连接,上传下载的等功能。
1、概念简介
1.1、什么是FTP?
FTP是FileTransferProtocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于Internet上的控制文件的双向传输。
同时,它也是一个应用程序(Application)。基于不同的操作系统有不同的FTP应用程序,而所有这些应用程序都遵守同一种协议以传输文件。
在FTP的使用当中,用户经常遇到两个概念:”下载”(Download)和”上传”(Upload)。
“下载”文件就是从远程主机拷贝文件至自己的计算机上;”上传”文件就是将文件从自己的计算机中拷贝至远程主机上。
用Internet语言来说,用户可通过客户机程序向(从)远程主机上传(下载)文件。
1.2、什么是FTPS?
FTPS是一种对常用的文件传输协议(FTP)添加传输层安全(TLS)和安全套接层(SSL)加密协议支持的扩展协议。
FTPS不应与基于SSH的SSH文件传输协议或是Secure FTP协议相混淆。
换句话说,就是FTP的扩展,添加了加密操作。
1.3、什么是SFTP?
SFTP(sftp)一般指SSH文件传输协议。
在计算机领域,SSH文件传输协议(英语:SSH File Transfer Protocol,也称Secret File Transfer Protocol,中文:安全文件传送协议,英文:Secure FTP或字母缩写:SFTP)是一数据流连接,提供文件访问、传输和管理功能的 络传输协议。
1.4、概念小结
通俗的讲,FTP,FTPS 属于同一种协议的远程文件管理系统。FTPS是在FTP的基础上添加了安全层,需要我们使用软件安装。SFTP是基于SSH协议,我们SSH开启,并且开启了22端口,就可以直接连接进行文件管理。
2、依赖包准备
FTP和FTPS我们选用ftp4j来实现文件管理,SFTP我们使用jsch来实现文件管理。
<dependencies> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency> <!--连接SFTP--> <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.54</version> </dependency></dependencies>
ftp4j可能在maven中央仓库不存在,这里提供一个官方链接去下载源码,打入自己的nexus私服即可。
ftp4j下载地址:
http://www.sauronsoftware.it/projects/ftp4j/download.php
下载后的源码拷贝到您的项目,结构如下:
因为我们采用直接拷贝源码方式集成到项目,所以如同如下结构:
3、工具类实现
3.1、定义FTP统一接口IFtpHelper
定义了一些FTP的基本操作,获取FTP客户端,获取根目录,连接FTP服务器,切换目录,遍历目录,断开连接,检查目录是否存在,下载文件,上传文件,删除文件等操作。
/** * FTP操作统一接口 */public interface IFtpHelper<T> { /** * 获取客户端 * @return 客户端 FTP(S)对应FtpClient, SFTP对应ChannelSftp */ T getClient(); /** * 获取FTP/FTPS/SFTP所处根目录 * @return 根目录 */ String getRootPath(); /** * 创建连接 * @param ftpServer FTP服务器IP * @param ftpPort FTP服务器端口 * @param ftpUsername FTP连接用户名 * @param ftpPassword FTP连接密码 */ void connect(String ftpServer, int ftpPort, String ftpUsername, String ftpPassword); /** * 检查目录是否存在 * @param dirName 目录名称 */ boolean checkDirectory(String dirName); /** * 根据上级目录列出下级目录的名称列表 * @param dir 上级目录名称 * @return 下级目录名称列表 */ String[] listDir(String dir); /** * 断开连接 */ void disconnect(); /** * 切换目录 * @param path 目录path * @throws Exception */ void changeDirectory(String path); /** * 下载文件到输出流 * @param filePath 文件路径 * @return 输出流(没有关闭,需要调用者自己关闭) * @throws Exception */ OutputStream downloadFile(String filePath) throws Exception; /** * 上传文件 * @param file 要上传的本地文件 * @param filePath 上传到FTP服务的所在目录 * @throws Exception */ void uploadFile(File file, String filePath) throws Exception; /** * 删除远程FTP文件 * @param filePath 远程FTP文件目录 * @throws Exception */ void deleteFile(String filePath) throws Exception;}
3.2、使用模板方法抽象类定义模板
实现了一些公共的方法,比如获取客户端(通过泛型),获取根目录路径等。
/** * Ftp 工具类 基础父类 */public abstract class BaseFtpHelper<T> implements IFtpHelper<T> { /** * 客户端(FTP/FTPS/SFTP) */ protected T ftp; /** * 根目录 */ protected String rootPath; /** * 初始化Ftp信息 * @param ftpServer ftp服务器地址 * @param ftpPort Ftp端口 * @param ftpUsername ftp 用户名 * @param ftpPassword ftp 密码 */ public BaseFtpHelper(String ftpServer, int ftpPort, String ftpUsername, String ftpPassword) { connect(ftpServer, ftpPort, ftpUsername, ftpPassword); } /** * 将文件路径替换为一个正确的路径 windows不处理 * @param path 文件路径 */ public static String replaceFilePath(String path){ if (StringUtils.isBlank(path)){ return ""; } if (path.trim().equals("/")){ return path.trim(); } // 反斜杠转正 双正斜杠去重 path = path.replaceAll("\\", "/"); while (path.contains("//")){ path = path.replaceAll("//", "/"); } if (path.endsWith("/")){ return path.substring(0, path.length() - 1); } return path; } @Override public T getClient() { return ftp; } @Override public String getRootPath() { return rootPath; }}
3.3、FTP工具类实现
/** * Ftp 工具类 */public class FtpHelper extends BaseFtpHelper<FTPClient>{ /** * 初始化Ftp信息 * * @param ftpServer ftp服务器地址 * @param ftpPort Ftp端口 * @param ftpUsername ftp 用户名 * @param ftpPassword ftp 密码 */ public FtpHelper(String ftpServer, int ftpPort, String ftpUsername, String ftpPassword) { super(ftpServer, ftpPort, ftpUsername, ftpPassword); } /** * 连接到ftp * @param ftpServer ftp服务器地址 * @param ftpPort Ftp端口 * @param ftpUsername ftp 用户名 * @param ftpPassword ftp 密码 */ public void connect(String ftpServer, int ftpPort, String ftpUsername, String ftpPassword) { ftp = new FTPClient(); try { ftp.connect(ftpServer, ftpPort); ftp.login(ftpUsername, ftpPassword); ftp.setCharset("UTF-8"); // 记录根目录 this.rootPath = ftp.currentDirectory(); System.out.println(this.rootPath); } catch (Exception e) { ftp = null; throw new FtpException(e.getMessage(), e.getCause()); } } /** * 更改ftp路径 * @param dirName * @return */ public boolean checkDirectory(String dirName) { boolean flag; try { ftp.changeDirectory(dirName); flag = true; } catch (Exception e) { flag = false; } return flag; } /** * 遍历目录 * @param dir 目录名称 * @return 子目录列表 */ public String[] listDir(String dir){ // 不是目录,则直接返回, 校验的同时会进入目录 if (!checkDirectory(dir)){ return new String[]{}; } // 查询目录下面有什么 String[] dirs = new String[]{}; try { dirs = ftp.listNames(); } catch (Exception e) { e.printStackTrace(); } return dirs; } /** * 断开ftp链接 */ public void disconnect() { try { if (ftp.isConnected()) { ftp.disconnect(true); } } catch (Exception e) { e.printStackTrace(); } } /** * 读取ftp文件流 * * @param filePath ftp文件路径 * @return s * @throws Exception */ public OutputStream downloadFile(String filePath) throws Exception { OutputStream outputStream = new ByteArrayOutputStream(); String fileName = ""; filePath = StringUtils.removeStart(filePath, "/"); int len = filePath.lastIndexOf("/"); if (len == -1) { if (filePath.length() > 0) { fileName = filePath; } else { throw new Exception("没有输入文件路径"); } } else { fileName = filePath.substring(len + 1); String type = filePath.substring(0, len); String rootStart = rootPath; rootStart = StringUtils.removeStart(rootStart, "/"); if (type.startsWith(rootStart)){ type = type.substring(rootStart.length() + 1); } String[] typeArray = type.split("/"); // 先切换到根目录,预防出错 ftp.changeDirectory(rootPath); for (String s : typeArray) { ftp.changeDirectory(s); } } try { final String pwd = ftp.currentDirectory(); ftp.download(fileName, outputStream, 0, null); } catch (Exception e) { e.printStackTrace(); } return outputStream; } /** * 上传文件到ftp * * @param file 文件对象 * @param filePath 上传的路径 * @throws Exception */ public void uploadFile(File file, String filePath) throws Exception { InputStream inStream = new FileInputStream(file); uploadFile(inStream, filePath); } /** * 上传文件到ftp * * @param inStream 上传的文件流 * @param filePath 上传路径 * @throws Exception */ public void uploadFile(InputStream inStream, String filePath) throws Exception { if (inStream == null) { return; } String fileName = ""; filePath = StringUtils.removeStart(filePath, "/"); int len = filePath.lastIndexOf("/"); if (len == -1) { if (filePath.length() > 0) { fileName = filePath; } else { throw new Exception("没有输入文件路径"); } } else { fileName = filePath.substring(len + 1); String type = filePath.substring(0, len); String rootStart = rootPath; rootStart = StringUtils.removeStart(rootStart, "/"); if (type.startsWith(rootStart)){ type = type.substring(rootStart.length() + 1); } String[] typeArray = type.split("/"); // 先切换到根目录,预防出错 ftp.changeDirectory(rootPath); for (String s : typeArray) { if (!checkDirectory(s)) { ftp.createDirectory(s); } } } ftp.upload(fileName, inStream, 0, 0, null); } /** * 删除ftp文件 * * @param filePath 文件路径 * @throws Exception */ public void deleteFile(String filePath) throws Exception { String fileName = ""; filePath = StringUtils.removeStart(filePath, "/"); int len = filePath.lastIndexOf("/"); if (len == -1) { if (filePath.length() > 0) { fileName = filePath; } else { throw new Exception("没有输入文件路径"); } } else { fileName = filePath.substring(len + 1); String type = filePath.substring(0, len); String[] typeArray = type.split("/"); for (String s : typeArray) { if (checkDirectory(s)) { ftp.changeDirectory(s); } } } ftp.deleteFile(fileName); } /** * 切换目录 * * @param path * @throws Exception */ public void changeDirectory(String path) { if (!StringUtils.isEmpty(path)) { try { ftp.changeDirectory(path); } catch (Exception e) { e.printStackTrace(); } } }}
3.4、FTPS工具类实
import com.itdl.exception.FtpException;import it.sauronsoftware.ftp4j.FTPClient;import org.apache.commons.lang3.StringUtils;import javax.net.ssl.SSLContext;import javax.net.ssl.SSLSocketFactory;import javax.net.ssl.TrustManager;import javax.net.ssl.X509TrustManager;import java.io.*;import java.security.SecureRandom;import java.security.cert.X509Certificate;/** * Ftps 工具类 */public class FtpsHelper extends BaseFtpHelper<FTPClient>{ /** * 初始化Ftp信息 * * @param ftpServer ftp服务器地址 * @param ftpPort Ftp端口 * @param ftpUsername ftp 用户名 * @param ftpPassword ftp 密码 */ public FtpsHelper(String ftpServer, int ftpPort, String ftpUsername, String ftpPassword) { super(ftpServer, ftpPort, ftpUsername, ftpPassword); } /** * 连接到ftp * @param ftpServer ftp服务器地址 * @param ftpPort Ftp端口 * @param ftpUsername ftp 用户名 * @param ftpPassword ftp 密码 */ public void connect(String ftpServer, int ftpPort, String ftpUsername, String ftpPassword) { ftp = new FTPClient(); try { TrustManager[] trustManager = new TrustManager[]{new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } }}; SSLContext sslContext = null; sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, trustManager, new SecureRandom()); SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); ftp.setSSLSocketFactory(sslSocketFactory); ftp.setSecurity(FTPClient.SECURITY_FTPES); ftp.connect(ftpServer, ftpPort); ftp.login(ftpUsername, ftpPassword); ftp.setCharset("UTF-8"); // 记录根目录 this.rootPath = ftp.currentDirectory(); System.out.println(this.rootPath); } catch (Exception e) { ftp = null; throw new FtpException(e.getMessage(), e.getCause()); } } /** * 更改ftp路径 * @param dirName * @return */ public boolean checkDirectory(String dirName) { boolean flag; try { ftp.changeDirectory(dirName); flag = true; } catch (Exception e) { flag = false; } return flag; } /** * 遍历目录 * @param dir 目录名称 * @return 子目录列表 */ public String[] listDir(String dir){ // 不是目录,则直接返回, 校验的同时会进入目录 if (!checkDirectory(dir)){ return new String[]{}; } // 查询目录下面有什么 String[] dirs = new String[]{}; try { dirs = ftp.listNames(); } catch (Exception e) { e.printStackTrace(); } return dirs; } /** * 断开ftp链接 */ public void disconnect() { try { if (ftp.isConnected()) { ftp.disconnect(true); } } catch (Exception e) { e.printStackTrace(); } } /** * 读取ftp文件流 * * @param filePath ftp文件路径 * @return s * @throws Exception */ public OutputStream downloadFile(String filePath) throws Exception { OutputStream outputStream = new ByteArrayOutputStream(); String fileName = 声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!