You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java实现FTP服务器全目录递归下载(同步)问题求助

解决FTP递归同步目录到本地的问题

我明白你现在的困境啦——已经能搞定FTP根目录下的文件和文件夹创建,但子文件夹里的内容还没法同步下来对吧?其实只需要把你当前的逻辑改成递归方法就行,让程序遇到文件夹时自动钻进去处理里面的内容,处理完再回到上一级目录继续。

核心思路

当程序遍历到FTP上的文件夹时:

  1. 先在本地创建对应的目录
  2. 切换到FTP的这个子目录
  3. 递归调用同样的方法来处理该子目录下的所有内容
  4. 处理完成后切回FTP的父目录,避免后续路径混乱

修改后的完整代码

我基于你的原代码调整出了可递归的版本,完全兼容Apache Commons Net库:

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class FtpSync {

    public static void main(String[] args) {
        FTPClient ftp = new FTPClient();
        try {
            // 填入你的FTP连接配置
            ftp.connect("your-ftp-host", 21);
            ftp.login("your-username", "your-password");
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE); // 建议用二进制模式,避免非文本文件损坏

            // 定义FTP根目录和本地目标目录
            String remoteRootDir = "/";
            String localRootDir = "D:/your-local-folder/";

            // 启动递归下载
            downloadDirectory(ftp, remoteRootDir, localRootDir);

            ftp.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 递归下载FTP目录到本地
     * @param ftp 已连接登录的FTPClient实例
     * @param remoteDirPath FTP上的远程目录路径
     * @param localDirPath 本地对应的目录路径
     * @throws IOException FTP操作异常
     */
    private static void downloadDirectory(FTPClient ftp, String remoteDirPath, String localDirPath) throws IOException {
        // 递归创建本地目录(包括父目录)
        File localDir = new File(localDirPath);
        if (!localDir.exists()) {
            boolean created = localDir.mkdirs();
            if (created) {
                System.out.println("创建本地目录: " + localDirPath);
            }
        }

        // 切换到FTP的当前远程目录
        ftp.changeWorkingDirectory(remoteDirPath);

        // 获取当前目录下的所有文件和文件夹
        FTPFile[] files = ftp.listFiles();
        for (FTPFile file : files) {
            String fileName = file.getName();
            // 跳过FTP默认的.和..目录,避免无限递归
            if (fileName.equals(".") || fileName.equals("..")) {
                continue;
            }

            String remoteFilePath = remoteDirPath + "/" + fileName;
            String localFilePath = localDirPath + File.separator + fileName;

            if (file.isFile()) {
                // 下载文件,用try-with-resources自动关闭输出流
                System.out.println("正在下载: " + remoteFilePath);
                try (OutputStream os = new BufferedOutputStream(new FileOutputStream(localFilePath))) {
                    ftp.retrieveFile(fileName, os);
                }
            } else if (file.isDirectory()) {
                // 递归处理子目录
                System.out.println("进入子目录: " + remoteFilePath);
                downloadDirectory(ftp, remoteFilePath, localFilePath);
            }
        }

        // 处理完当前目录后,切回FTP父目录
        ftp.changeToParentDirectory();
        System.out.println("返回父目录: " + ftp.printWorkingDirectory());
    }
}

几个关键注意点

  • 用mkdirs()代替mkdir():如果本地父目录不存在,mkdir()会创建失败,mkdirs()会自动递归创建所有必要的父目录。
  • 跳过.和..:FTP的listFiles()会返回这两个特殊目录,必须跳过,否则会陷入无限递归循环。
  • 二进制模式传输:调用ftp.setFileType(FTPClient.BINARY_FILE_TYPE),确保图片、压缩包等非文本文件不会损坏。
  • 自动关闭流:用try-with-resources语法管理OutputStream,避免资源泄漏。
  • 切回父目录:处理完子目录后一定要调用changeToParentDirectory(),不然后续的文件路径会出错。

内容的提问来源于stack exchange,提问作者user9066907

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:16:49