java - 如何使用 Files.newDirectoryStream 和递归以特定方式打印目录树?
问题描述
例如,我有一个文件夹“大学”。我需要按如下所示的方式打印“大学”内的所有文件夹和文件:
university
├── file.txt
├── floor 1
│ └── room 102
│ └── file.txt
├── floor 2
│ ├── left wing
│ │ ├── kitchen
│ │ │ └── kitchen.txt
│ │ └── room 232
│ └── right wing
│ └── room 252
│ ├── file1.txt
│ └── file2.txt
└── floor 3
└── room 374
└── file.txt
我可以使用递归和 Files.newDirectoryStream() 方法,或 Files.list() 作为模拟。我知道我的问题的一些解决方案,比如二叉树或类似的东西,但我只能使用我所说的。
这是我尝试过的:
public class Main {
private static final String UNIVERSITY = "university";
private static final Path UNIVERSITY_FOLDER = Paths.get(UNIVERSITY);
private static final StringBuffer result = new StringBuffer();
public static void main(String[] args) throws IOException {
createTree(UNIVERSITY_FOLDER);
}
private static void printTree(Path path) throws IOException {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
Iterator<Path> iter = stream.iterator();
while (iter.hasNext()) {
Path currentFile = iter.next();
appendSpaces(currentFile);
if (iter.hasNext()) {
result.append("├── ");
} else {
result.append("└── ");
}
result.append(currentFile.getFileName());
result.append(System.lineSeparator());
if (Files.isDirectory(currentFile)) {
printTree(currentFile);
}
}
} catch (DirectoryIteratorException ex) {
throw ex.getCause();
}
}
private static void createTree(Path path) throws IOException {
result.append(path.getFileName());
result.append(System.lineSeparator());
printTree(path);
System.out.println(result.toString());
}
private static void appendSpaces(Path path) {
for (int i = 0; i < (path.getNameCount() - 2); i++) {
result.append("│ ");
}
}
}
我的代码正在运行,但它会打印出类似的内容:
university
├── file.txt
├── floor 1
│ └── room 102
│ │ └── file.txt
├── floor 2
│ ├── left wing
│ │ ├── kitchen
│ │ │ └── kitchen.txt
│ │ └── room 232
│ └── right wing
│ │ └── room 252
│ │ │ ├── file1.txt
│ │ │ └── file2.txt
└── floor 3
│ └── room 374
│ │ └── file.txt
我需要一个额外的条件来打印这个符号“│”,但也许我走错了路。我将不胜感激。
解决方案
正如您在房间 252 中看到的元素,当您 时printSpaces
,您需要打印 3 个“缩进”,并且您的代码始终打印"| "
为缩进。但是它需要为 252 打印的是"| "
第一个缩进,但" "
作为第二个和第三个缩进。
但是再想象一下 3 楼有一个 375 房间,那么对于 374 房间的条目,您必须打印" "
第一个缩进和"| "
第二个缩进。
这表明打印缩进的代码(当前传递一个列出要打印的缩进数量的单个数字)从根本上被破坏了。它需要传递一个数组或其他类似列表的结构。你不通过'3',而是通过'true,false,false'或类似这些线的东西。
更糟糕的是,您当前将文件名传递给 appendSpaces 并编写一些代码对其进行路径深度分析,以了解甚至有多少缩进,这只是一个非首发:给定的路径只是不知道,每个缩进,无论您需要画线还是只需要一个空白块。
有很多解决方案,但最常用的一种是使用递归助手。对于大多数递归算法,您需要一些变量来跟踪诸如“多少缩进”之类的信息(或者在这种情况下,一堆标志,每个缩进一个,以指示是否绘制条形图)。对于第一次调用(您的代码的一个用户进行),这些跟踪器变量没有任何意义,因此您需要创建一个帮助程序。因此,而不是:
public static void printTree(... params ...) {
// code that will eventaully call printTree recursively
}
你这样做:
public static void printTree(.... params ...) {
printTree0(param1, param2, param3, new boolean[0]);
}
private static void printTree0(... params ..., boolean[] indents) {
// code that calls printTree0 recursively
}
这是一个非常常见的模式:
公共方法只包含一个调用私有方法的单行代码,以相同的顺序传递所有参数,此外还有一些变量,全部为初始值(0,或者在这种情况下,是一个空的布尔数组,表示根级别不需要缩进)。
私有方法(附加 a
0
是一种常见的 java 习惯用法,表示“这是一个辅助方法”)是递归编写的,公共方法不是。
您的indents
跟踪器变量包含这些标志,是否打印条形图。
每次递归时,您都会创建一个新的布尔数组,并添加正确的缩进:
boolean[] newIndents = Arrays.copyOf(indents, indents.length + 1);
newIndents[indents.length] = true or false (depending on whether you want bars or not).
从那里我相信你可以弄清楚,因为你几乎完成了任务。
推荐阅读
- node.js - 使用 fs.stat() 获取文件状态,使用 inode 编号,而不是路径
- c++ - 链接列表:在将链接列表显示为 0 和 NULL 给出相同答案时,我应该在“while 循环”中使用什么?
- pytorch - RuntimeError:为 DataParallel 加载 state_dict 时出错:state_dict 中出现意外键:“module.scibert_layer.embeddings.position_ids”
- azure - Azure COSMOS DB 在每场比赛中名列前茅
- html - 将 Rmarkdown 编织到 HTML 时,在图形上方添加标题和在图形下方添加注释
- php - Symfony 4.4.26 Sonata 管理员。格式化程序小部件不起作用
- mysql - 添加上一年的结果
- html - 移动视图时Jquery点击功能不起作用
- firebase - 用于 Firebase 身份验证的 Facebook 身份验证模拟器
- html - ...工作正常,但...给出错误