Java封装FTP(S)/SFTP实现文件上传下载

很多时候我们会遇到从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进行处理,非常感谢!

上一篇 2022年8月27日
下一篇 2022年8月27日

相关推荐