在 ftp 服务器中不递归列出文件、目录、子文件和子目录的想法

Ideas for listing files, directories, sub files & sub directories without recursion in ftp server

我正在尝试生成给定目录的文件列表及其在 ftp 服务器中的子目录。

服务器运行良好,我已经成功生成了当前目录的文件列表。当我尝试列出子目录和它们的文件时,事情变得复杂了。

我被要求不要使用递归算法,所以我自己做了一些研究。我曾尝试使用线程(对于找到的每个目录,启动一个新线程),但我无法保持连接稳定和打开。关于如何使用线程或其他替代方法正确执行此操作的任何想法?

编辑:下面是我的代码,当使用递归语句(最后一行代码)时,它有效

   class TEST {
        public static synchronized void main(String[] args) {
        String server = args[0]; //server,path will be given as an arguments
        String pass = "SOMEPASS";
        String user = "SOMEUSER";
        int port = 21;
        FTPClient ftpClient = new FTPClient();
        try {
            ftpClient.connect(server, port);
            showServerReply(ftpClient);
            int replyCode = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                System.out.println("Connect failed");
                return;
            }
            boolean success = ftpClient.login(user, pass);
            showServerReply(ftpClient);
            if (!success) {
                System.out.println("Could not login to the server");
                return;
            }
           /*START THE FILE LISTING HERE*/

        } catch (IOException ex) {
            System.out.println("Oops! Something wrong happened");
            ex.printStackTrace();
        } finally {
            // logs out and disconnects from server
            try {
                if (ftpClient.isConnected()) {
                    ftpClient.logout();
                    ftpClient.disconnect();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
    private static void showServerReply(FTPClient ftpClient) {
        String[] replies = ftpClient.getReplyStrings();
        if (replies != null && replies.length > 0) {
            for (String aReply : replies) {
                System.out.println("SERVER: " + aReply);
            }
        }
    }
    private static void scanDir(FTPClient client, String path) throws IOException {
        FTPFile[] files = client.listFiles(path); // Search all the files in the current directory
        
        for (int j = 0; j < files.length; j++) {
            System.out.println(files[j].getName()); // Print the name of each files
        }
        FTPFile[] directories = client.listDirectories(path); // Search all the directories in the current directory
        for (int i = 0; i < directories.length; i++) {
            String dirPath = directories[i].getName();
            System.out.println(dirPath); // Print the path of a sub-directory
            scanDir(client,dirPath); // Call recursively the method to display the files in the sub-directory DONT WANT TO DO THAT...
        }
    }
}

好的,这是一个示例,说明如何使用列表非递归地处理它。

请注意,此示例基于/访问本地文件系统,但可以很容易地 rewritten/extended 用于任何类型的 hierarchial/recursive 结构。

package Whosebug.nonrecursivefilesearch;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.stream.Stream;

public class NonRecursiveFileSearch {

    public static void main(final String[] args) throws IOException {
        final File searchDir = new File("D:\test\maven-test"); // set one

        System.out.println("\nOld Java");
        printDirs(listFiles_old(searchDir, true, true), "OLD: Depth first, include dirs");
        printDirs(listFiles_old(searchDir, true, false), "OLD: Breadth first, include dirs");
        printDirs(listFiles_old(searchDir, false, true), "OLD: Depth first, exclude dirs");
        printDirs(listFiles_old(searchDir, false, false), "OLD: Breadth first, exclude dirs");

        System.out.println("\nNew java.io with streams");
        printDirs(listFiles_newIO(searchDir, true), "Java NIO, include dirs");
        printDirs(listFiles_newIO(searchDir, false), "Java NIO, exclude dirs");
    }

    /**
     * this is the way to 'manually' find files in hierarchial/recursive structures
     *
     * reminder: "Depth First" is not a real depth-first implementation
     * real depth-first would iterate subdirs immediately.
     * this implementation iterates breadth first, but descends into supdirs before it handles same-level directories
     * advantage of this implementation is its speed, no need for additional lists etc.
     *
     * in case you want to exclude recursion traps made possible by symbolic or hard links, you could introduce a hashset/treeset with
     * visited files (use filename strings retrieved with canonicalpath).
     * in the loop, check if the current canonical filename string is contained in the hash/treeset
     */
    static public ArrayList<File> listFiles_old(final File pDir, final boolean pIncludeDirectories, final boolean pDepthFirst) {
        final ArrayList<File> found = new ArrayList<>();
        final ArrayList<File> todo = new ArrayList<>();

        todo.add(pDir);

        while (todo.size() > 0) {
            final int removeIndex = pDepthFirst ? todo.size() - 1 : 0;
            final File currentDir = todo.remove(removeIndex);
            if (currentDir == null || !currentDir.isDirectory()) continue;

            final File[] files = currentDir.listFiles();
            for (final File file : files) {
                if (file.isDirectory()) {
                    if (pIncludeDirectories) found.add(file);
                    // additional directory filters go here
                    todo.add(file);
                } else {
                    // additional file filters go here
                    found.add(file);
                }
            }
        }

        return found;
    }

    static private void printDirs(final ArrayList<File> pFiles, final String pTitle) {
        System.out.println("====================== " + pTitle + " ======================");
        for (int i = 0; i < pFiles.size(); i++) {
            final File file = pFiles.get(i);
            System.out.println(i + "\t" + file.getAbsolutePath());
        }
        System.out.println("============================================================");
    }

    /**
     * this is the java.nio approach. this is NOT be a good solution for cases where you have to retrieve/handle files in your own code.
     * this is only useful, if the any NIO class provides support. in this case, NIO class java.nio.file.Files helps handling local files.
     * if NIO or your target system does not offer such helper methods, this way is harder to implement, as you have to set up the helper method yourself.
     */
    static public Stream<Path> listFiles_newIO(final File pDir, final boolean pIncludeDirectories) throws IOException {
        final Stream<Path> stream = Files.find(pDir.toPath(), 100,
                (path, basicFileAttributes) -> {
                    final File file = path.toFile(); // conversion to File for easier access (f.e. isDirectory()), could also use NIO methods
                    return (pIncludeDirectories || !file.isDirectory() /* additional filters go here */ );
                });
        return stream;

    }
    static private void printDirs(final Stream<Path> pStream, final String pTitle) {
        System.out.println("====================== " + pTitle + " ======================");
        pStream.forEach(System.out::println);
        System.out.println("============================================================");
    }
}

A​​ND,必须添加,java.nio.file.Files.find() 可以递归实现。但是因为它只是一个调用,所以这也可以算作 'non-recursive'。

此外,正如 OP 在评论中所述,可以使用 Stack 或其他 FIFO/LIFO 集合。混合深度优先的 LIFO,广度优先方法的 FIFO。