读取网络驱动器上的所有文件和文件夹



假设您有一个任务来读取保存在某个文件夹中的所有文件并处理每个文件。为简单起见,假设所有文件都是 HTML 文件,并且您希望从中提取 HTML 内容。

在Java 8中,有Files.walk API,它允许我们做类似的事情。下面是一个示例:

try (Stream<Path> paths = Files.walk(Paths.get("/home/you/Desktop"))) {
paths
.filter(Files::isRegularFile)
.forEach(System.out::println);
}

如果您必须处理少量文件夹和文件,这听起来非常好,但是如果您有数以百万计的文件分布在多个网络驱动器上,那么此过程将需要很长时间,并且显然需要暂停。在这种情况下如何进行并行性的任何想法?

我认为没有一个简单的通用算法来解决你的问题。

事实上,在处理分布在许多节点上的大量数据时,一般的想法是让每个节点收集数据并在单个节点中处理这些部分结果。

从单个系统进行所有扫描将很困难。

要进行一些真正的优化,您不能以相同的方式处理所有文件夹。

您可以做的是创建一个可以并行扫描的PathsCollection

因此,与其沿着单个根行走,不如沿着多个文件夹(每个网络驱动器可能一个(开始多次行走

为此,您需要知道哪个路径是网络路径,哪个是本地路径。

例如,如果您有一个文件夹,其中每个子文件夹都是一个装载的网络驱动器,则可以轻松收集所有这些文件夹,并为每个文件夹并行运行您的漫游

我会做类似于以下代码的事情:

public class ParallelWalks {
ExecutorService executor = Executors.newCachedThreadPool();
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
public static void main(String[] args) {
new ParallelWalks().exec();
}

public ExecutorService executorSelector(Path path) {
if(isNetworkDrive(path)) {
return executor;
}else {
return singleThreadExecutor;
}
}

private boolean isNetworkDrive(Path path) {
// Here goes the logic to choose which path should go on a different
// thread.
return path.toString().contains("srv");
}

private void exec() {
Path path = Paths.get("/home/you/Desktop");
try (Stream<Path> files = Files.list(path)) {
files.forEach(this::taskRunner);
} catch (IOException e) {
// Do something with the exception
}
}
private void taskRunner(final Path path) {
executorSelector(path)
.submit(() -> doWalk(path));
}
private void doWalk(Path path) {
try (Stream<Path> paths = Files.walk(path)) {
paths.filter(Files::isRegularFile).forEach(System.out::println);
} catch (IOException e) {
// Do something with the exception
}
}
}

这样,将按顺序处理所有本地目录,并且将在他的线程上处理所有网络驱动器。

仅当所有(或大部分(网络驱动器共享相同的装入点父级时,它才有效。

否则,您应该实现自己的步行

最新更新