将递归文件系统遍历转换为流

在学习编程的时候,回到Turbo Pascal时代,我设法使用FindFirstFindNextFindClose函数在目录中列出文件。 首先,我想出了一个打印给定目录内容的过程。 您可以想象我为能够真正从自身调用该过程以递归遍历文件系统而感到自豪。 好吧,那时我还不知道递归一词,但是它确实有用。 Java中的类似代码如下所示:

public void printFilesRecursively(final File folder) {for (final File entry : listFilesIn(folder)) {if (entry.isDirectory()) {printFilesRecursively(entry);} else {System.out.println(entry.getAbsolutePath());}}
}private File[] listFilesIn(File folder) {final File[] files = folder.listFiles();return files != null ? files : new File[]{};
}

不知道File.listFiles()可以返回null ,是吗? 这就是它发出I / O错误的信号,就像IOException不存在一样。 但这不是重点。 System.out.println()很少是我们所需要的,因此该方法既不可重用也不可组合。 这可能是“ 打开/关闭”原理的最佳反例。 我可以想象文件系统递归遍历的几个用例:

  1. 获取所有文件的完整列表以供显示
  2. 查找与给定模式/属性匹配的所有文件(还要检出File.list(FilenameFilter)
  3. 搜索一个特定文件
  4. 处理每个文件,例如通过网络发送

上面的每个用例都有一系列独特的挑战。 例如,我们不想建立所有文件的列表,因为在开始处理它之前将花费大量的时间和内存。 我们希望通过流水线计算(但没有笨拙的访问者模式)来处理文件的发现和延迟。 另外,我们还希望使搜索短路以避免不必要的I / O。 幸运的是,在Java 8中,其中一些问题可以通过流解决:

final File home = new File(FileUtils.getUserDirectoryPath());
final Stream<Path> files = Files.list(home.toPath());
files.forEach(System.out::println);

请记住, Files.list(Path) (Java 8中的新增功能)没有考虑子目录,我们将在以后进行修复。 这里最重要的一课是: Files.list()返回Stream<Path> –我们可以传递,组合,映射,过滤等的值。它非常灵活,例如,计算我拥有的文件数非常简单在每个扩展名的目录中:

import org.apache.commons.io.FilenameUtils;//...final File home = new File(FileUtils.getUserDirectoryPath());
final Stream<Path> files = Files.list(home.toPath());
final Map<String, List<Path>> byExtension = files.filter(path -> !path.toFile().isDirectory()).collect(groupingBy(path -> getExt(path)));byExtension.forEach((extension, matchingFiles) ->System.out.println(extension + "\t" + matchingFiles.size()));//...private String getExt(Path path) {return FilenameUtils.getExtension(path.toString()).toLowerCase();
}

好吧,您可能会说,只是另一个API。 但是一旦我们需要更深入 ,递归遍历子目录,它就会变得非常有趣。 流的一项惊人功能是,您可以通过各种方式将它们相互组合。 老Scala说“ flatMap that shit”在这里也适用,请查看以下递归Java 8代码:

//WARNING: doesn't compile, yet:private static Stream<Path> filesInDir(Path dir) {return Files.list(dir).flatMap(path ->path.toFile().isDirectory() ?filesInDir(path) :singletonList(path).stream());
}

filesInDir()延迟生成的Stream<Path>包含目录中的所有文件,包括子目录。 您可以通过调用map()filter()anyMatch()findFirst()等将其用作任何其他流。但是它实际上如何工作? flatMap()map()类似,但是map()是直接的1:1转换, flatMap()允许用多个条目替换输入Stream中的单个条目。 如果使用map() ,则最终会得到Stream<Stream<Path>> (或者可能是Stream<List<Path>> )。 但是flatMap()通过展开内部条目来展平该结构。 让我们看一个简单的例子。 想象Files.list()返回两个文件和一个目录。 对于文件, flatMap()随该文件一起接收一个元素的流。 我们不能简单地返回该文件,而必须对其进行包装,但实际上这是无操作的。 对于目录,它变得更加有趣。 在这种情况下,我们递归地调用filesInDir() 。 结果,我们获得了该目录的内容流,并将其注入到外部流中。

上面的代码简短,甜美,并且…无法编译。 这些讨厌的人再次检查了异常。 这是一个固定的代码,包装检查过的异常以保持理智:

public static Stream<Path> filesInDir(Path dir) {return listFiles(dir).flatMap(path ->path.toFile().isDirectory() ?filesInDir(path) :singletonList(path).stream());
}private static Stream<Path> listFiles(Path dir) {try {return Files.list(dir);} catch (IOException e) {throw Throwables.propagate(e);}
}

不幸的是,这种相当优雅的代码还不够懒。 flatMap()急切求值,因此即使我们几乎不要求第一个文件,它始终会遍历所有子目录。 您可以尝试使用我的小型LazySeq库,该库尝试提供甚至更lazy-seq抽象,类似于Scala中的流或Clojure中的lazy-seq 。 但是,即使是标准的JDK 8解决方案也可能确实有用,并且可以大大简化您的代码。

翻译自: https://www.javacodegeeks.com/2014/07/turning-recursive-file-system-traversal-into-stream.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362567.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Webpack 2 视频教程 002 - NodeJS 安装与配置

原文发表于我的技术博客 这是我免费发布的高质量超清「Webpack 2 视频教程」。 Webpack 作为目前前端开发必备的框架&#xff0c;Webpack 发布了 2.0 版本&#xff0c;此视频就是基于 2.0 的版本讲解的。 这个基本就是目前国内最好的 Webpack 2.0 最好的学习视频了&#xff0c;…

vue+elementUI 添加多个可以全选的多选框

elementUI-checkbox官网&#xff1a;https://element.eleme.cn/#/zh-CN/component/checkbox 一、要做上面这种效果&#xff0c;首先要了解全选框中indeterminate 状态和v-model的变量的关系 参考 -Dayer-&#xff1a; <el-checkbox :indeterminate"isIndeterminate&…

WMI in C#[强类型操作]

C# 进行WMI操作的内容封装在System.Management.dll中&#xff0c;具体的在MSDN有详细描述&#xff0c;默认是用[“**’]去读取和设置属性等。 此处介绍一个自动生成强类型的包装软件&#xff0c;这样处理起来就简单了很多&#xff0c;不用在反复的查看参数等信息了。 1、 使用W…

JSR 303从I18N属性文件加载消息

总览 本文将说明如何适应JSR 303验证API来从I18n属性文件加载消息&#xff0c;并通过保留国际化的所有好处和对多种语言的支持来实现这一点。 为此&#xff0c;我们将实现一个基于Spring API的自定义MessageInterpolator&#xff0c;用于管理I18N消息。 依存关系 在进行这项工…

2019年ipa发布苹果应用商店审核指南

https://baijiahao.baidu.com/s?id1623886553597961077&wfrspider&forpc ipa 发布审核指南 说明&#xff1a; 本指南为初版&#xff0c;旨在帮助非技术人员快速了解苹果ipa发布审核流程非技术的审核专员发布审核只需处理 &#xff08;五&#xff09;、iTunes connect …

GridView生成序号

一个经常碰到的情况&#xff1a;GridView需要添加一个序号列&#xff0c;并且从1开始自动编号。而数据库中的ID往往是不连续的&#xff08;会有记录被删除的情况&#xff09;&#xff0c;我们无法绑定现有字段作为编号。因此我们需要手动给GridView编号。 思路&#xff1a;在Gr…

[前端优化]使用Microsoft Ajax Minifier对资源文件进行压缩优化

在前端优化中&#xff0c;js、css等文件的优化一般都是压缩的优化&#xff0c;进行合并、减小体积以达到减小请求的目的。 今天发现了一个集成在VS中的压缩插件&#xff0c;使得压缩变得比较快捷。 配置方法 首先需要去下载Microsoft Ajax Minifier&#xff0c;一路安装就可以&…

手把手教你用 elementUI 实现导航栏

elementUI导航栏官网 1. 安装 elementUI 2. 文件准备 3. 配置路由 4. 导航栏代码 一、安装 elementUI npm i element-ui -S&#xff1b; 在 main.js 中注册组件&#xff1a; import ElementUI from element-ui; import element-ui/lib/theme-chalk/index.css; Vue.use(Elem…

Java 8编写自定义收集器简介

Java 8引入了收集器的概念。 大多数时候&#xff0c;我们几乎不使用Collectors类中的工厂方法&#xff0c;例如collect(toList()) &#xff0c; toSet()或其他更花哨的方法&#xff0c;例如counting()或groupingBy() 。 实际上&#xff0c;没有多少人真正去研究如何定义和实现收…

vuex+element 从后台获取数据写导航栏-菜单权限

主要用到 vuex、router.beforeEach、router.addRoutes()。vuex 的使用方法可以看我的另一篇博客&#xff1a;vue笔记&#xff08;四&#xff09;vuex。 顺便安利一个 在线视频转gif图。 因为第一次用到 router.addRoutes()&#xff0c;在做这个需求的时候遇到了很多问题&…

Sql Server全局变量(转)

Sql Server一共提供了30多个全局变量常用:IDENTITY : 返回最后插入行的标识列的列值。ERROR : 返回最后执行的Transact-SQL语句的错误代码。没有错误则为零。ROWCOUNT : 返回受上一语句影响的行数&#xff0c;任何不返回行的语句将这一变量设置为0。DBTS : 返回当前数据库的…

P3393 逃离僵尸岛 最短路dijkstra

题目描述 小a住的国家被僵尸侵略了&#xff01;小a打算逃离到该国唯一的国际空港逃出这个国家。 该国有N个城市&#xff0c;城市之间有道路相连。一共有M条双向道路。保证没有自环和重边。 K个城市已经被僵尸控制了&#xff0c;如果贸然闯入就会被感染TAT...所以不能进入。由其…

jquery 给iframe里的元素添加事件

$("#iframeId").on("load", function(event){//判断 iframe是否加载完成 这一步很重要$("#divId",this.contentDocument).click(function(){//添加点击事件alert("就是这样");}); });更多专业前端知识&#xff0c;请上 【猿2048】www…

JavaFX技巧7:使用CSS颜色常量/派生颜色

在使用FlexCalendarFX时&#xff0c;我不得不定义一组颜色以可视化不同颜色的不同日历的控件。 每个日历不仅提供一种颜色&#xff0c;还提供几种&#xff1a;用于取消选择/选定/悬停状态的背景和文本颜色。 颜色曾在多个地方使用过&#xff0c;但为了简洁起见&#xff0c;我仅…

spring step 1 : 什么是spring

学习一门技术之前还是花点时间来看看这门技术的特点&#xff0c;我们通过使用这种技术能够达到什么效果。 1.spring是什么&#xff1f; 2.spring能够干什么&#xff1f; 3.为什么使用spring&#xff1f; 1.spring是一个开源的框架&#xff0c;主要是由IoC&#xff0c;AOP&#…

文字溢出显示三个点

1、单行溢出 text-overflow: ellipsis; overflow: hidden; white-space: nowrap; width: 90%; 2、多行溢出 overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; 转载于:https://www.cnblogs.co…

import() 动态加载component组件失败

在写 vueelement 从后台获取数据写导航栏 时&#xff0c;当我加载动态路由&#xff0c;import() 总是失败。 假设 path: “/views/Home.vue”&#xff0c;name: “Home”。 一、使用 import() 语法加载组件 参考&#xff1a;“Cookysurongbin”的 解决vue动态路由异步加载im…

JPA /休眠刷新策略初学者指南

介绍 在我之前的文章中&#xff0c;我介绍了实体状态转换 对象关系映射范例。 当刷新当前持久性上下文时&#xff0c;所有管理实体状态转换都将转换为关联的数据库语句。 Hibernate的刷新行为并不总是像人们想象的那么明显。 后写 Hibernate尝试将持久性上下文刷新推迟到最后…

进入登录页时,用户名输入框自动聚焦、按enter键让密码框聚焦,完整输入信息后登录

让element-ui的输入框聚焦的4种方式 思路&#xff1a;&#xff08;可以跳过这一步看完整代码——完整代码&#xff09; 1. 进入页面时&#xff0c;用户名输入框就要获取焦点&#xff0c;使用 自定义指令 聚焦更方便。当然也可以用 ref 在 mounted() 钩子函数中让输入框聚焦。 …

JS的对象及其属性和方法

在JavaScript中是基于对象的编程&#xff0c;而不是完全的面向对象的编程。       那麽什麽是对象呢&#xff1f;如果你学过一些VB的编程&#xff0c;对这个名词一定不会陌生。通俗的说&#xff0c;对象是变量的集合体&#xff0c;对象提供对于数据的一致的组织手段&…