Code Monkey home page Code Monkey logo

java-ftp-example's Introduction

该仓库为博客记录示例,如果需要可以前往博客查看内容 Java 使用 FTP/SFTP

Java 使用 FTP/SFTP

场景

项目中需要使用 FTP,所以做了简单的 FTP/SFTP 封装,此处仅做一下记录。

注:这里并未实现连接池管理,生产环境强烈建议手动实现连接池以提高性能!

UML 图像说明

形状

注:此处参考自 IDEA UML 图中的颜色

  • 蓝色:类/步骤
  • 黄色:字段
  • 红色:函数
  • 紫色:配置

图形

  • 长方形:类/配置文件/依赖项
  • 圆角长方形:字段/函数/对象/变量
  • 箭头:拥有/向下依赖的意思

目标

封装简单的通用操作

  • 上传单个文件
  • 上传使用 InputStream(内存操作)
  • 下载单个文件
  • 下载得到 InputStream(内存操作)
  • 创建目录
  • 递归创建目录
  • 删除单个文件/空目录
  • 获取指定目录下的文件信息列表
  • 获取文件/目录信息
  • 递归获取文件/目录信息
  • 递归删除目录
  • 监听目录变化(内部使用)
  • 异步上传后等待结果

思路

  1. 定义顶层接口 FtpOperator,具体实现由子类(BasicFtpOperatorImpl, SftpOperatorImpl)完成
  2. 定义顶层配置文件基类 FtpClientConfig,包含着 ftp 连接必须的一些东西,具体细节在子类配置中 BasicFtpClientConfig, SftpClientConfig
  3. 添加工厂类 FtpOperatorFactory,根据不同子类的配置对象创建不同的 ftp 操作对象,并且一经创建就可以永久性使用
  4. 添加 FtpWatchConfig, FtpWatch, FtpWatchFactory FTP 监听器
  5. 添加集成 SpringBoot 中,读取 application.yml 中的配置,并创建不同的 FtpOperator 暴露给外部使用,动态初始化 FTP 监视器

注:这里使用 FTP 监视器的原因是为了避免每次上传数据后都要单独监听 FTP 目录的变化,造成 FTP 多线程连接数量过多 注:这里的并未实现 FTPClient 及 Jsch 的对象池管理,所以仅可参考实现,生产环境中仍需进行修改!

图解如下

图解

实现

具体的代码吾辈就不贴到这里了,全部的代码已经放到 GitHub 的公共仓库 上了。

FTP 使用

FtpOperator API 图解
FtpOperator API 图解

上传部分流程图解
上传部分流程图解

使用 FtpOperator 进行基本操作

@RunWith(SpringRunner.class)
@SpringBootTest
public class FtpSpringConfigTest {
    private final Logger log = LoggerFactory.getLogger(getClass());
    @Autowired
    private FtpOperator ftp;

    @Test
    public void put() throws UnsupportedEncodingException {
        // 上传数据
        final ByteArrayInputStream is = new ByteArrayInputStream("测试数据".getBytes("UTF-8"));
        final boolean result = ftp.put(is, "/test.txt");
        assertThat(result)
                .isTrue();
    }

    @Test
    public void exist() {
        // 判断数据是否存在于 ftp 服务器
        final boolean exist = ftp.exist("/test.txt");
        assertThat(exist)
                .isTrue();
    }

    @Test
    public void get() {
        // 从 ftp 服务器上下载数据
        ftp.get("/test.txt", is -> {
            try {
                final List<String> list = IOUtils.readLines(is);
                log.info("list: {}", list);
                assertThat(list)
                        .isNotEmpty();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        });
    }

    @Test
    public void mkdir() {
        // 创建文件夹
        assertThat(ftp.mkdir("/test"))
                .isTrue();
    }

    @Test
    public void mkdirR() {
        // 递归创建文件夹
        assertThat(ftp.mkdirR("/test/test2/test3"))
                .isTrue();
    }

    @Test
    public void ls() {
        // 获取目录下的文件信息列表
        final List<Stat> list = ftp.ls("/");
        log.info("list: {}", list.stream()
                .map(Stat::getPath)
                .collect(Collectors.joining("\n")));
        assertThat(list)
                .isNotEmpty();
    }

    @Test
    public void lsr() {
        // 获取目录下的文件信息列表
        final List<Stat> list = ftp.lsR("/");
        log.info("list: {}", list.stream()
                .map(Stat::getPath)
                .collect(Collectors.joining("\n")));
        assertThat(list)
                .isNotEmpty();
    }

    @Test
    public void rm() {
        // 删除单个文件
        assertThat(ftp.rm("/test.txt"))
                .isTrue();
    }

    @Test
    public void rmdir() {
        // 删除指定空目录
        assertThat(ftp.rmdir("/test/test2/test3"))
                .isTrue();
    }

    @Test
    public void rmdirR() {
        // 递归删除指定目录
        assertThat(ftp.rmdirR("/test"))
                .isTrue();
    }
}

使用 FtpOperator 上传文件并监听结果

@RunWith(SpringRunner.class)
@SpringBootTest
public class FtpSpringConfigTest extends BaseTest {
    private final Logger log = LoggerFactory.getLogger(getClass());
    @Autowired
    private FtpOperator ftp;
    @Test
    public void watch() throws InterruptedException, UnsupportedEncodingException {
        // 监听新文件 /test.md 的出现
        final String path = "/test.md";
        ftp.watch((Predicate<String>) str -> str.equals(path))
                .thenAcceptAsync(stat -> {
                    log.warn("stat: {}", stat);
                    assertThat(ftp.exist(stat.getPath()))
                            .isNotNull();
                });
        // 创建测试文件
        final ByteArrayInputStream is = new ByteArrayInputStream("测试数据".getBytes("UTF-8"));
        log.warn("test file upload completed!");
        assertThat(ftp.put(is, path))
                .isTrue();
        // 注意,这里有一个问题就是如果程序结束的太快,那么更新将变得不可能的!
        Thread.sleep(2000);
        // 删除测试文件
        ftp.rm(path);
    }
}

那么,关于 Java 中使用 FTP/SFTP 便到此为止啦

java-ftp-example's People

Contributors

rxliuli avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.