使用Java(Apache Net Commons)下载整个FTP目录

4
我正在尝试递归遍历登录FTP服务器后到达的整个根目录。我已经成功连接,但我真正想做的是递归遍历整个结构并下载每个文件和文件夹,并使其与FTP上的结构相同。我已经编写了一个可行的下载方法,它可以访问服务器并获取我的所有文件结构,这很棒,但第一次尝试失败,第二次尝试才能成功。我得到的错误如下: java.io.FileNotFoundException: output-directory\test\testFile.png (系统找不到指定的路径) 我已经成功上传了本地目录的功能,但无法使下载工作,在多次尝试后我真的需要一些帮助。
public static void download(String filename, String base)
{
    File basedir = new File(base);
    basedir.mkdirs();

    try
    {
        FTPFile[] ftpFiles = ftpClient.listFiles();
        for (FTPFile file : ftpFiles)
        {
            if (!file.getName().equals(".") && !file.getName().equals("..")) {
                // If Dealing with a directory, change to it and call the function again
                if (file.isDirectory())
                {
                    // Change working Directory to this directory.
                    ftpClient.changeWorkingDirectory(file.getName());
                    // Recursive call to this method.
                    download(ftpClient.printWorkingDirectory(), base);

                    // Create the directory locally - in the right place
                    File newDir = new File (base + "/" + ftpClient.printWorkingDirectory());
                    newDir.mkdirs();

                    // Come back out to the parent level.
                    ftpClient.changeToParentDirectory();
                }
                else
                {
                    ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
                    String remoteFile1 = ftpClient.printWorkingDirectory() + "/" + file.getName();
                    File downloadFile1 = new File(base + "/" + ftpClient.printWorkingDirectory() + "/" + file.getName());
                    OutputStream outputStream1 = new BufferedOutputStream(new FileOutputStream(downloadFile1));
                    boolean success = ftpClient.retrieveFile(remoteFile1, outputStream1);
                    outputStream1.close();
                }
            }
        }
    }
    catch(IOException ex)
    {
        System.out.println(ex);
    }
}

已添加代码以展示当前代码的确切状态。顺便感谢您的快速回复。 - Slippy
如果您能提及哪个部分的过程让您感到困难,那么帮助您确实会更容易 - 是在下载文件时遇到问题吗?遍历远程目录?递归遍历?保留文件夹结构? - Deltharis
你应该知道每个目录中的前两个文件通常是“.”和“..”,它们分别代表当前目录和父目录。你应该检查它们并跳过它们,否则你会得到一些非常奇怪的结果。 - RealSkeptic
修改了代码并添加了检查(并在上面的示例中进行了更新)-我似乎陷入了一个无限循环,试图获取根目录,而没有真正进入其他目录。 - Slippy
使用 != 比较字符串? - RealSkeptic
显示剩余8条评论
2个回答

1
您的问题(在我们摆脱了“.”和“..”,并且您解决了二进制问题后)是在调用 newDir.mkdirs()之前执行递归步骤。因此,假设您有这样一棵树:
.
..
someDir
   .
   ..
   someFile.txt
someOtherDir
   .
   ..
someOtherFile.png

你需要做的是跳过点文件,看到 someDir 是一个目录,然后立即进入它,跳过它的点文件,看到 someFile.txt 并处理它。你还没有在本地创建 someDir,所以会出现异常。
你的异常处理程序不会停止执行,因此控制权返回递归的上一级。此时,它创建了该目录。
所以下次运行程序时,本地的 someDir 目录已经从上一次运行中创建,你就不会遇到问题。
基本上,你应该更改你的代码为:
            if (file.isDirectory())
            {
                // Change working Directory to this directory.
                ftpClient.changeWorkingDirectory(file.getName());

                // Create the directory locally - in the right place
                File newDir = new File (base + "/" + ftpClient.printWorkingDirectory());
                newDir.mkdirs();

                // Recursive call to this method.
                download(ftpClient.printWorkingDirectory(), base);

                // Come back out to the parent level.
                ftpClient.changeToParentDirectory();
            }

非常感谢您在这里提供的所有帮助!这无疑是我在Stack Overflow上得到的最好的帮助,您让我自己解决问题并随着进展进行必要的更改。与其只是给我一堆代码,我学到了一些新的有趣的东西 :) - Slippy

1
一个完整的独立代码,可以递归地从FTP文件夹中下载所有文件:
private static void downloadFolder(
    FTPClient ftpClient, String remotePath, String localPath) throws IOException
{
    System.out.println("Downloading folder " + remotePath + " to " + localPath);

    FTPFile[] remoteFiles = ftpClient.listFiles(remotePath);

    for (FTPFile remoteFile : remoteFiles)
    {
        if (!remoteFile.getName().equals(".") && !remoteFile.getName().equals(".."))
        {
            String remoteFilePath = remotePath + "/" + remoteFile.getName();
            String localFilePath = localPath + "/" + remoteFile.getName();

            if (remoteFile.isDirectory())
            {
                new File(localFilePath).mkdirs();

                downloadFolder(ftpClient, remoteFilePath, localFilePath);
            }
            else
            {
                System.out.println("Downloading file " + remoteFilePath + " to " +
                    localFilePath);

                OutputStream outputStream =
                    new BufferedOutputStream(new FileOutputStream(localFilePath));
                if (!ftpClient.retrieveFile(remoteFilePath, outputStream))
                {
                    System.out.println("Failed to download file " + remoteFilePath);
                }
                outputStream.close();
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接