简而言之就是情况:
for(element : array)
{
execute something that adds new elements to the array;
}
很明显,新添加的元素不会被处理。是否有一种技术可以处理每个元素?
以下是此问题的一个示例:我想,在给定文件夹的情况下,深入了解并将所有文件(在其子项下或其子项下)移动到指定文件夹下。之后删除所有空文件夹:
Parent Folder
- Level1Folder1
- file1_1
- Level1Folder2
- Level2Folder1
- file2_1
- file2_2
- file1_2
将成为:
Parent Folder
- file1_1
- file1_2
- file2_1
- file2_2
这是我的代码药水:
public static void moveUpOneFolder(Path parent) {
try (DirectoryStream<Path> ds1 = Files.newDirectoryStream(parent)) {
for (Path p1 : ds1) {
//if this node is a dir, traverse its content
if (Files.isDirectory(p1)) {
moveUpOneFolder(p1);
}
//if this node is a file, move it up one level
else {
Path newFileName = parent.getParent().resolve(p1.getName(p1.getNameCount() - 2) + "_" + p1.getFileName());
Files.move(p1, newFileName);
}
Files.delete(p1);
}
} catch (IOException e) {
e.printStackTrace();
}
}
此递归不起作用,因为当执行到达Level2Folder1时,它将file2_1和文件2_2移动到Level1Folder2,然后继续将file1_2移动到父文件夹,忽略file2_1和file2_2,即文件夹中新添加的元素。发生这种情况是因为ds1已经为for循环初始化,新元素没有添加到此数组/流中,因此被忽略。
我想这对经验丰富的程序员来说并不困难,但我真的被卡住了。 : - )
答案 0 :(得分:6)
Java Collections通过抛出ConcurrentModificationException
来拒绝此问题。 ;)
在这种特殊情况下,我倾向于推荐一种队列式结构;而不是使用for
循环,重复出列元素并将更多元素添加到队列的后面。
答案 1 :(得分:2)
为什么需要一次将文件移到一个目录中?我认为这是你问题的根源,你正在创建一个过于复杂的解决方案。相反,如果您以一种稍微不同的方式解决问题,并将组件的行为分成几部分,则可以避免遇到的问题。在伪java代码中:
public void moveAllFiles(File fromDir, File toDir) {
for(File f : getAllFilesAndDirs(fromDir)) {
if(f.isDirectory()) {
moveAllFiles(f, toDir);
f.delete();
} else {
move(f, toDir);
}
}
}
请注意以下几点:
fromDir
和toDir
分开,没有必要要求它们位于同一位置,这样我们就可以递归地使用该调用。fromDir
的所有孩子,只要没有其他程序修改目录,我们就不再关心目录是否会更改,从而避免了并发修改问题。答案 2 :(得分:1)
在向其添加元素时,您无需迭代数组。这将抛出各种ConcurrentModificationException
。
使用Java的NIO,扁平化目录结构并不难。将所有文件复制到临时目录,随时删除。然后从该临时目录复制回根目录。
final Path root = Paths.get("/root");
final Path temp = Files.createTempDirectory(null);
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (attrs.isRegularFile()) {
Files.copy(file, temp.resolve(file.getFileName()));
Files.delete(file);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (!dir.equals(root))
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
Files.walkFileTree(temp, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (attrs.isRegularFile()) {
Files.copy(file, root.resolve(file.getFileName()));
Files.delete(file);
}
return FileVisitResult.CONTINUE;
}
});
这将使您的目录结构变得扁平化,只保留文件并丢弃目录。
答案 3 :(得分:1)
我建议使用Stack
或Queue
而不是数组。这意味着您将继续循环,直到数据结构为空。在循环期间,您添加了需要处理的元素(即包含应移动的文件的目录)。