FTP SDK使用示例


FTP 服务器 (File Transfer Protocol Server) 是在互联网上提供文件存储和访问服务的计算机,它们依照 FTP协议 (文件传输协议) 提供服务。

下面将介绍其相关的 Java SDK 使用示例

一 、连接服务

1. 依赖导入

还是老规矩,首先新建 Maven 工程并导入 FTP 相关依赖,因为后续涉及到对象序列化这里引入了 Jackson

<dependency>
    <groupId>commons-net</groupId>
    <artifactId>commons-net</artifactId>
    <version>3.6</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.3</version>
</dependency>

2. 创建连接

通过 FTPClient 初始化连接对象。

public void init() throws IOException {
    FTPClient ftpClient = new FTPClient();
    // Connect
    ftpClient.connect("192.168.0.20", 21);
    ftpClient.setDataTimeout(120000);

    if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
        // failed than disconnect
        ftpClient.disconnect();
    }

    // Login to ftp
    if (ftpClient.login("budai", "123456")) {
        ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
        // Passive connection mode
        ftpClient.enterLocalPassiveMode();
        // Encoding
        ftpClient.setControlEncoding("GBK");
        // Language code
        FTPClientConfig clientConfig = new FTPClientConfig(ftpClient.getSystemType().split(" ")[0]);
        clientConfig.setServerLanguageCode("zh");
        ftpClient.configure(clientConfig);
    } else {
        System.out.println("Login to server failed");
    }
}

二、目录管理

1. 创建目录

通过 makeDirectory() 方法创建新的目录。

public void create() throws IOException {
    boolean isCreate = ftpClient.makeDirectory("/file/test");
    System.out.println("Create success? " + isCreate);
}

2. 切换目录

通过 changeWorkingDirectory() 方法用于切换到指定目录下,同时可利用该方法判断相应目录是否存在。

public void check() throws IOException {
    boolean isExist = ftpClient.changeWorkingDirectory("/file/test");
    System.out.println("Path { /file/test } is exist? " + isExist);

    // 切换到父路径下
    ftpClient.changeToParentDirectory();
    System.out.println("Change to parent, current path: " + ftpClient.printWorkingDirectory());
}

3. 删除目录

通过 removeDirectory() 方法删除已存在的目录。

public void remove() throws IOException {
    boolean isDeleted = ftpClient.removeDirectory("/file/test");
    System.out.println("Directory { /file/test } is deleted? " + isDeleted);
}

4. 目录监控

FTPClient 并不提供默认的目录监控接口,想要实现动态监控目录变化就需要自行实现。

实现访问也很简单,通过 listFiles() 实时获取最新的文件集合,并于旧的文件集取差集即可实现动态目录监控的效果。

public void monitorDirectory(String monitorPath) throws Exception {
    List<String> fileName = Arrays.stream(ftpClient.listFiles(monitorPath))
              .map(FTPFile::getName)
              .collect(Collectors.toList());
    System.out.println("Start monitoring directory: " + monitorPath);
    while (true) {
        List<String> latestList = Arrays.stream(ftpClient.listFiles(monitorPath))
                .map(FTPFile::getName)
                .collect(Collectors.toList());
        latestList.removeAll(fileName);
        if (latestList.size() > 0) {
            System.out.println("Detect new file: " + latestList);
        }
        TimeUnit.SECONDS.sleep(2);
    }
}

三、文件管理

1. 上传文件

通过 storeFile() 方法上传本地文件至服务器。

public void uploadFile() {
    String remotePath = "/test/ftp-1.txt";
    String localPath = "src\\main\\resources\\ftp\\ftp-1.txt";
    try (InputStream in = new FileInputStream(localPath)) {
        // Upload file
        boolean isUpload = ftpClient.storeFile(remotePath, in);
        System.out.println(isUpload);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

2. 下载文件

通过 retrieveFile() 方法下载服务器文件。

public void downloadFile() {
    String remotePath = "/test/ftp-1.txt";
    String localPath = "src\\main\\resources\\ftp\\ftp-1.txt";
    try (OutputStream fos = new FileOutputStream(localPath)) {
        // Download file
        boolean isSave = ftpClient.retrieveFile(remotePath, fos);
        System.out.println(isSave);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

3. 遍历文件

通过 listFiles() 方法可获取指定目录下的所有文件。

public void listFile() throws IOException {
    FTPFile[] files = ftpClient.listFiles("/file");
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    for (FTPFile file : files) {
        String updateDate = sdf.format(file.getTimestamp().getTime());
        System.out.println(file.getName() + "_" + updateDate);
    }
}

4. 移动文件

移动文件一共有两种方式,最原始的方式就是先获取文件再重新上传,最后删除原目录下的文件。

当然 FTPClient 也提供更简单接口用于移动文件,即 rename() 方法,其作用效果类似 Linux 环境下的 mv 命令。

public void moveFile() {
    // Manual move
    try (InputStream in = ftpClient.retrieveFileStream("/test/11.txt")) {
        ftpClient.storeFile("/bak/11.txt", in);
        ftpClient.deleteFile("/test/11.txt");
    } catch (IOException e) {
        e.printStackTrace();
    }

    // Equal to linux "mv"
    ftpClient.rename("/test/11.txt", "/bak/11.txt");
} 

5. 删除文件

通过 deleteFile() 方法即可删除指定文件。

public void deleteOldFile() throws IOException {
    ftpClient.changeWorkingDirectory("/file/test");
    try {
        ftpClient.deleteFile("hello.txt");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

四、数据管理

1. 上传数据

在之前介绍了如何将本地文件上传至 FTP 服务器,但如果需要上传项目运行中的数据呢?

这里我用到了 GZIPJackson 工具,将需要保存的 Java 对象序列化为字符串,再保存为 GZIP 文件上传至服务器,实现代码如下:

public void uploadData() throws IOException {
    String putPath = "/test/store";
    String filePath = putPath + "/" + UUID.randomUUID() + ".gz";
    // Compress content to gzip
    User user = new User("123", "Alex", "123456");
    byte[] bytes = GZIPUtil.compress(objectMapper.writeValueAsBytes(user));

    // Upload file
    try (InputStream in = new ByteArrayInputStream(bytes)) {
    if (ftpClient.storeFile(filePath, in)) {
        System.out.println("Upload file: 【" + filePath + "】 success.");
    }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

2. 下载数据

下载则比较简单了,与和之前下载文件一样,然后再对下载的 GZIP 文件进行解压转化即可。

public void downloadData(String filePath) {
    try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
        // Receive ftp file
        ftpClient.retrieveFile(filePath, os);
        // Uncompress zip to java bean
        byte[] bytes = GZIPUtil.uncompress(os.toByteArray());
        User user = objectMapper.readValue(bytes, User.class);
        System.out.println("Receive: " + user);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

3. GZIP工具

上述中涉及的 GZIP 数据加压缩工具方法如下:

/**
  * 压缩为 GZIP 字节数组
  */
public static byte[] compress(byte[] bytes) {
    try (
          ByteArrayOutputStream out = new ByteArrayOutputStream();
          GZIPOutputStream gzip = new GZIPOutputStream(out);
    ) {
        gzip.write(bytes);
        gzip.close();
        return out.toByteArray();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

/**
  * GZIP 解压缩
  */
 public static byte[] uncompress(byte[] bytes) {
    try (
          ByteArrayInputStream in = new ByteArrayInputStream(bytes);
          GZIPInputStream unzip = new GZIPInputStream(in);
          ByteArrayOutputStream out = new ByteArrayOutputStream();
    ) {
        byte[] buffer = new byte[1024];
        int n;
        while ((n = unzip.read(buffer)) >= 0) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

文章作者: 烽火戏诸诸诸侯
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 烽火戏诸诸诸侯 !
  目录