Dart笔记:glob 文件系统遍历

Dart笔记
文件系统遍历工具:glob 模块

作者李俊才 (jcLee95):https://blog.csdn.net/qq_28550263
邮箱 :291148484@163.com
本文地址:https://blog.csdn.net/qq_28550263/article/details/134423951


很久前介绍过一个 NodeJS 中的类似工具,叫做 fast-glob,可参见《NodeJS文件系统遍历工具:fast-glob》一文(地址:https://jclee95.blog.csdn.net/article/details/129892856)。这类库对于自己开发底层工具来说是比较常用的。比如在前端中自己去做一些脚手架。本文介绍的 glob库就是 Dart 语言中这样一个类似的工具,在很多常用的命令行工具中,都有它的使用,比如 build_runner 库(一个用于 Dart 代码生成和模块化编译的构建系统),再比如 very_good_cli 等等。当需要自己做类似的 Flutter/Dart 项目的工程化工具时,可以回过头来参考本文中介绍的相关知识。


1. 概述

glob 库是一个强大的文件系统遍历工具,它提供了一种简洁的方式来描述和匹配文件路径模式。这种模式被称为 glob 模式,它可以包含各种通配符,使得我们可以轻松地匹配多个文件或目录。

glob 库的主要功能是根据给定的 glob 模式来查找和匹配文件系统中的文件和目录。它支持各种通配符,包括 *(匹配任意数量的字符)、?(匹配任意一个字符)、[abc](匹配任意一个列出的字符)等等。此外,它还支持使用 {} 来指定多个模式,以及使用 ** 来匹配任意深度的目录。

在 Dart 和 Flutter 的项目中,glob 库被广泛用于各种工程化工具中,如 build_runner(一个用于 Dart 代码生成和模块化编译的构建系统)和一些cli 工具中。当我们需要开发自己的工程化工具时,glob 库将是一个非常有用的工具。

2. glob 库入门

2.1 安装 glob 库

和安装其它的 Dart/Flutter 模块一样。首先,你需要在项目的 pubspec.yaml 文件中添加 glob 库的依赖。在 dependencies 部分添加以下代码:

  dependencies:glob: ^2.1.2

然后,运行 flutter或dart pub get 命令来下载和安装 glob 库:

dart pub get

这样,glob 库就被成功安装到你的项目中了。

或者直接使用 pub add 命令安装当前发布的最新版本:

flutter pub add glob

着将自动添加依赖到 pubspec.yaml 文件中并隐式运行 pub get命令。

2.2 初体验:使用 glob 库进行文件匹配

使用 glob 库进行文件匹配也非常简单。首先,你需要导入 glob 库:

import 'package:glob/glob.dart';

然后,你可以创建一个 Glob 对象,并使用 matches 方法来检查一个路径是否匹配给定的 glob 模式:

var glob = Glob('**.dart');
if (glob.matches('lib/main.dart')) {print('The path matches the glob pattern');
} else {print('The path does not match the glob pattern');
}

3. glob 模式的基本语法

3.1 glob 模式中的 通配符

在 glob 模式中,* 字符匹配除 / 之外的零个或多个任何字符。这意味着它可以用来匹配给定目录中匹配模式的所有文件,而不会匹配子目录中的文件。例如,lib/*.dart 将匹配 lib/glob.dart,但不匹配 lib/src/utils.dart

** 是类似 *,但也匹配 /。它对于匹配文件或递归列出目录很有用。例如,lib/**.dart 将匹配 lib/glob.dartlib/src/utils.dart

? 字符匹配除 / 之外的单个字符。与 * 不同,它不会匹配多于或少于一个字符。例如,test?.dart 将匹配 test1.dart,但不匹配 test10.darttest.dart

3.2 glob 模式中的 字符集

[...] 构造匹配几个字符中的一个。它可以包含单个字符,如 [abc],在这种情况下,它将匹配任何这些字符;它可以包含范围,如 [a-zA-Z],在这种情况下,它将匹配任何落在范围内的字符;或者它可以包含两者的混合。它只会匹配一个字符。例如,test[a-zA-Z_].dart 将匹配 testx.darttestA.darttest_.dart,但不匹配 test-.dart

如果它以 ^! 开头,构造将匹配所有未提到的字符。例如,test[^a-z].dart 将匹配 test1.dart,但不匹配 testa.dart

3.3 glob 模式中的 选择器

{...,...} 构造匹配几个选项中的一个,每个选项都是一个 glob。例如,lib/{*.dart,src/*} 匹配 lib/glob.dartlib/src/data.txt。它可以包含大于一个的任何数量的选项,甚至可以包含嵌套的选项。

3.4 glob 模式中的 目录匹配

所有 globs 使用 POSIX 路径语法,包括使用 / 作为目录分隔符,无论它们在哪个平台上。这对于 Windows 根目录也是如此;例如,匹配 C 驱动器中所有文件的 glob 将是 C:/*

默认情况下,globPosix 系统和浏览器上是 区分大小写的,在 Windows 上不区分大小写。

4. 使用 glob 库进行文件系统遍历

4.1 如何使用 glob 库查找文件

使用 glob 库查找文件,你可以使用 Glob.list()Glob.listSync() 方法列出所有匹配 glob 的文件:

import 'package:glob/glob.dart';
import 'package:glob/list_local_fs.dart';final dartFile = Glob("**.dart");// 列出当前目录中的所有 Dart 文件。
void main(List<String> arguments) {for (var entity in dartFile.listSync()) {print(entity.path);}
}

在这个例子中,我们创建了一个 glob 模式 **.dart,它会匹配所有的 Dart 文件。然后,我们使用 listSync() 方法列出所有匹配这个模式的文件。

下面是一个新建的项目,运行 glob_demo.dart:
在这里插入图片描述
从图中可以看到,其输出结果为:

.\bin\glod_demo.dart
.\lib\glod_demo.dart
.\test\glod_demo_test.dart

4.2 如何使用 glob 库查找目录

使用 glob 库查找目录,你可以创建一个 glob 模式来匹配目录,然后使用 Glob.list()Glob.listSync() 方法列出所有匹配 glob 的目录:

import 'package:glob/glob.dart';
import 'package:glob/list_local_fs.dart';final directory = Glob("**/");// 列出当前目录中的所有子目录。
void main(List<String> arguments) {for (var entity in directory.listSync()) {print(entity.path);}
}

还是那个demo项目,其运行结果如图:
在这里插入图片描述
可以看到输出为:

.\.dart_tool
.\.dart_tool\package_config.json
.\.gitignore
.\analysis_options.yaml
.\bin
.\bin\glod_demo.dart
.\CHANGELOG.md
.\lib
.\lib\glod_demo.dart
.\pubspec.lock
.\pubspec.yaml
.\README.md
.\test
.\test\glod_demo_test.dart

在这个例子中,我们创建了一个 glob 模式 **/,它会匹配所有的子目录。然后,我们使用 listSync() 方法列出所有匹配这个模式的目录。

4.3 关于在 glob 库中 是否递归的说明

glob 库中,递归查找是通过 glob 模式中的 ** 来控制的。** 表示匹配任意深度的目录,因此,如果你在 glob 模式中使用了 **,那么 glob 库将会递归地查找所有子目录。

例如,以下代码将递归列出当前目录及其所有子目录中的所有 Dart 文件:

import 'package:glob/glob.dart';
import 'package:glob/list_local_fs.dart';final dartFile = Glob("**.dart");// 递归列出当前目录中的所有 Dart 文件。
void main(List<String> arguments) {for (var entity in dartFile.listSync()) {print(entity.path);}
}

在这个例子中,**.dart 会递归匹配当前目录及其所有子目录中的所有 Dart 文件。

如果你只想在当前目录(不包括子目录)中查找文件,你应该使用单个星号 *。例如,以下代码将只列出当前目录中的所有 Dart 文件,不会查找子目录:

import 'package:glob/glob.dart';
import 'package:glob/list_local_fs.dart';final dartFile = Glob("*.dart");// 列出当前目录中的所有 Dart 文件。
void main(List<String> arguments) {for (var entity in dartFile.listSync()) {print(entity.path);}
}

在这个例子中,*.dart 只会匹配当前目录中的 Dart 文件,不会匹配子目录中的文件。

5. list 和 listSync函数说明

这两个方法都是 Glob 类的扩展方法,定义在 package:glob/list_local_fs.dart 中。它们都用于列出匹配 glob 模式的文件系统实体(文件、目录等)。

/// Platform specific extensions for where `dart:io` exists, which use the
/// local file system.
extension ListLocalFileSystem on Glob {/// Convenience method for [Glob.listFileSystem] which uses the local file/// system.Stream<FileSystemEntity> list({String? root, bool followLinks = true}) =>listFileSystem(const LocalFileSystem(),root: root, followLinks: followLinks);/// Convenience method for [Glob.listFileSystemSync] which uses the local/// file system.List<FileSystemEntity> listSync({String? root, bool followLinks = true}) =>listFileSystemSync(const LocalFileSystem(),root: root, followLinks: followLinks);
}

使用时,需要做以下导入:

import 'package:glob/list_local_fs.dart';

5.1 list 方法

list 方法是一个异步方法,返回一个 Stream。这个 Stream 包含所有匹配 *glob 模式的文件系统实体。由于它是异步的,所以它不会阻塞主线程。

list 方法接受两个可选参数:rootfollowLinks

  • root 参数用于指定搜索的根目录,如果不指定,则默认为当前目录;
  • followLinks 参数决定是否跟随符号链接,如果设置为 true,则会跟随符号链接,否则不会。

list 方法内部调用了 listFileSystem 方法,并传入了一个 LocalFileSystem 实例,这表示它在本地文件系统上进行操作。

5.1 listSync 方法

listSync 方法是一个同步方法,返回一个 List,包含所有匹配 glob 模式的文件系统实体。由于它是同步的,所以它会立即返回所有匹配的文件系统实体。

listSync 方法也接受 rootfollowLinks 两个可选参数,含义与 list 方法中的相同。

listSync 方法内部调用了 listFileSystemSync 方法,并传入了一个 LocalFileSystem 实例,这表示它在本地文件系统上进行操作。

F. 附录

F.1 Glob 类

/// 用于引用 globs 的正则表达式。
final _quoteRegExp = RegExp(r'[*{[?\\}\],\-()]');/// 用于匹配和列出文件和目录的 glob。
///
/// glob 作为路径匹配整个字符串。虽然 glob 模式使用 POSIX 语法,但它可以匹配 POSIX、Windows 或 URL 路径。它期望路径使用的格式基于 [Glob.new] 的 `context` 参数;默认为当前系统的语法。
///
/// 在与 glob 匹配之前,路径会被规范化,所以例如 glob `foo/bar` 匹配路径 `foo/./bar`。相对 glob 可以匹配绝对路径,反之亦然;globs 和路径都被解释为相对于 `context.current`,默认为当前工作目录。
///
/// 当用作 [Pattern] 时,glob 将根据整个字符串是否匹配 glob 返回一个或零个匹配。这些匹配目前没有捕获组,尽管这可能在未来会改变。
class Glob implements Pattern {/// 用于创建此 glob 的模式。final String pattern;/// 根据此 glob 解释路径的上下文。final p.Context context;/// 如果为 true,如果路径匹配 glob 本身或递归地包含在匹配的目录中,则路径匹配。final bool recursive;/// glob 是否区分大小写匹配路径。bool get caseSensitive => _ast.caseSensitive;/// glob 的解析 AST。final AstNode _ast;/// 用于实现 [list] 和 [listSync] 的底层对象。////// 这不应在 [_listTreeForFileSystem] 之外直接读取。ListTree? _listTree;/// 跟踪之前使用的文件系统。如果这改变了,那么/// [_listTree] 必须被废弃。////// 这在 [_listTreeForFileSystem] 中处理。FileSystem? _previousFileSystem;/// [context] 的当前目录是否是绝对的。bool get _contextIsAbsolute =>_contextIsAbsoluteCache ??= context.isAbsolute(context.current);bool? _contextIsAbsoluteCache;/// [pattern] 是否可以匹配绝对路径。bool get _patternCanMatchAbsolute =>_patternCanMatchAbsoluteCache ??= _ast.canMatchAbsolute;bool? _patternCanMatchAbsoluteCache;/// [pattern] 是否可以匹配相对路径。bool get _patternCanMatchRelative =>_patternCanMatchRelativeCache ??= _ast.canMatchRelative;bool? _patternCanMatchRelativeCache;/// 返回 [contents],其中包含在 globs 中有意义的字符,这些字符被反斜杠转义。static String quote(String contents) =>contents.replaceAllMapped(_quoteRegExp, (match) => '\\${match[0]}');/// 使用 [pattern] 创建一个新的 glob。////// 根据 [context] 解释与 glob 匹配的路径。默认为系统上下文。////// 如果 [recursive] 为 true,此 glob 不仅匹配和列出它明确匹配的文件和目录,而且还匹配那些下面的任何内容。////// 如果 [caseSensitive] 为 true,此 glob 只匹配和列出那些大小写与 glob 中的字符匹配的文件。否则,它无论大小写都匹配。当 [context] 为 Windows 时,默认为 `false`,否则为 `true`。factory Glob(String pattern,{p.Context? context, bool recursive = false, bool? caseSensitive}) {context ??= p.context;caseSensitive ??= context.style == p.Style.windows ? false : true;if (recursive) pattern += '{,/**}';var parser = Parser(pattern, context, caseSensitive: caseSensitive);return Glob._(pattern, context, parser.parse(), recursive);}Glob._(this.pattern, this.context, this._ast, this.recursive);/// 列出在提供的 [fileSystem] 中与 glob 匹配的 [root] 下的所有 [FileSystemEntity]。////// 这与 [Directory.list] 工作方式类似,但它只列出可能包含匹配 glob 的实体的目录。它不保证返回实体的顺序,尽管它确保只返回给定路径的一个实体。////// [root] 默认为当前工作目录。////// [followLinks] 与 [Directory.list] 的工作方式相同。Stream<FileSystemEntity> listFileSystem(FileSystem fileSystem,{String? root, bool followLinks = true}) {if (context.style != p.style) {throw StateError("Can't list glob \"$this\"; it matches "'${context.style} paths, but this platform uses ${p.style} paths.');}return _listTreeForFileSystem(fileSystem).list(root: root, followLinks: followLinks);}/// 在提供的 [fileSystem] 中,同步列出在 [root] 下的所有与 glob 匹配的 [FileSystemEntity]。////// 这与 [Directory.listSync] 的工作方式类似,但它只列出可能包含匹配 glob 的实体的目录。它不保证返回实体的顺序,尽管它确保只返回给定路径的一个实体。////// [root] 默认为当前工作目录。////// [followLinks] 与 [Directory.list] 的工作方式相同。List<FileSystemEntity> listFileSystemSync(FileSystem fileSystem,{String? root, bool followLinks = true}) {if (context.style != p.style) {throw StateError("Can't list glob \"$this\"; it matches "'${context.style} paths, but this platform uses ${p.style} paths.');}return _listTreeForFileSystem(fileSystem).listSync(root: root, followLinks: followLinks);}/// 返回此 glob 是否匹配 [path]。bool matches(String path) => matchAsPrefix(path) != null;Match? matchAsPrefix(String path, [int start = 0]) {// Globs 就像锚定的 RegExps,只匹配整个路径,所以如果匹配从第一个字符之后的任何地方开始,它就不能成功。if (start != 0) return null;if (_patternCanMatchAbsolute &&(_contextIsAbsolute || context.isAbsolute(path))) {var absolutePath = context.normalize(context.absolute(path));if (_ast.matches(toPosixPath(context, absolutePath))) {return GlobMatch(path, this);}}if (_patternCanMatchRelative) {var relativePath = context.relative(path);if (_ast.matches(toPosixPath(context, relativePath))) {return GlobMatch(path, this);}}return null;}Iterable<Match> allMatches(String path, [int start = 0]) {var match = matchAsPrefix(path, start);return match == null ? [] : [match];}String toString() => pattern;/// 处理获取可能缓存的 [ListTree] 为 [fileSystem]。ListTree _listTreeForFileSystem(FileSystem fileSystem) {// 不要为内存文件系统使用缓存的树,以避免内存泄漏。if (fileSystem is MemoryFileSystem) return ListTree(_ast, fileSystem);// 如果文件系统不同,丢弃我们缓存的 `_listTree`。if (fileSystem != _previousFileSystem) {_listTree = null;_previousFileSystem = fileSystem;}return _listTree ??= ListTree(_ast, fileSystem);}
}

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

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

相关文章

第7天:信息打点-资产泄漏amp;CMS识别amp;Git监控amp;SVNamp;DS_Storeamp;备份

第7天&#xff1a;信息打点-资产泄漏&CMS识别&Git监控&SVN&DS_Store&备份 知识点&#xff1a; 一、cms指纹识别获取方式 网上开源的程序&#xff0c;得到名字就可以搜索直接获取到源码。 cms在线识别&#xff1a; CMS识别&#xff1a;https://www.yun…

基于单片机C51全自动洗衣机仿真设计

**单片机设计介绍&#xff0c; 基于单片机C51全自动洗衣机仿真设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机C51的全自动洗衣机仿真设计是一个复杂的项目&#xff0c;它涉及到硬件和软件的设计和实现。以下是对这…

SDUT OJ《算法分析与设计》搜索算法

A - 子集和问题 Description 子集和问题的一个实例为〈S,t〉。其中&#xff0c;S{ x1 &#xff0c; x2 &#xff0c;…&#xff0c;xn }是一个正整数的集合&#xff0c;c是一个正整数。子集和问题判定是否存在S的一个子集S1&#xff0c;使得&#xff1a; 。 试设计一个解子…

MATLAB与Excel的数据交互

准备阶段 clear all % 添加Excel函数 try Excel=actxGetRunningServer(Excel.Application); catch Excel=actxserver(Excel.application); end % 设置Excel可见 Excel.visible=1; 插入数据 % % 激活eSheet1 % eSheet1.Activate; % 或者 % Activate(eSheet1); % % 打开…

23.11.19日总结

经过昨天的中期答辩&#xff0c;其实可以看出来项目进度太慢了&#xff0c;现在是第十周&#xff0c;预计第十四周是终级答辩&#xff0c;在这段时间要把项目写完。 前端要加上一个未登录的拦截器&#xff0c;后端加上全局的异常处理。对于饿了么项目的商品建表&#xff0c;之前…

C语言:动态内存管理

目录 为什么存在动态内存分配 动态内存函数 malloc和free 示例 calloc 示例 realloc 示例 常见的动态内存错误 对NULL指针的解引用操作 对动态开辟的空间进行越界访问 对于非动态开辟内存使用free释放 使用free释放一块动态开辟内存的一部分 对同一块内存多次释…

fopen/fwrite/fread 对UNICODE字符写入的总结

windows对fopen函数进行了升级&#xff0c;可以支持指定文件的编码格式&#xff08;ccs参数指定&#xff09;。 例如&#xff1a; FILE *fp fopen("newfile.txt", "rt, ccsUTF-8"); 当以 ccs 模式打开文件时&#xff0c;进行读写操作的数据应为 UTF-16…

【SpringBoot3+Vue3】三【实战篇】-后端(优化)

目录 一、登录优化-redis 1、SpringBoot集成redis 1.1 pom 1.2 yml 1.3 测试程序&#xff08;非必须&#xff09; 1.4 启动redis&#xff0c;执行测试程序 2、令牌主动失效&#xff08;代码优化&#xff09; 2.1 UserController设置token到redis 2.2 登录拦截器Log…

mysql练习1

-- 1.查询出部门编号为BM01的所有员工 SELECT* FROMemp e WHEREe.deptno BM01; -- 2.所有销售人员的姓名、编号和部门编号。 SELECTe.empname,e.empno,e.deptno FROMemp e WHEREe.empstation "销售人员";-- 3.找出奖金高于工资的员工。 SELECT* FROMemp2 WHE…

FPGA设计时序约束八、others类约束之Set_Case_Analysis

目录 一、序言 二、Set Case Analysis 2.1 基本概念 2.2 设置界面 2.3 命令语法 2.4 命令示例 三、工程示例 四、参考资料 一、序言 在Vivado的时序约束窗口中&#xff0c;存在一类特殊的约束&#xff0c;划分在others目录下&#xff0c;可用于设置忽略或修改默认的时序…

综述:目标检测二十年(机翻版)(未完

原文地址 20年来的目标检测&#xff1a;一项调查 摘要关键词一 介绍二 目标检测二十年A.一个目标检测的路线图1)里程碑&#xff1a;传统探测器Viola Jones探测器HOG检测器基于可变形零件的模型&#xff08;DPM&#xff09; 2)里程碑&#xff1a;基于CNN的两阶段探测器RCNNSPPN…

Matlab绘制双坐标轴图示例函数yyaxis

一、前言 出于一些需求&#xff0c;我们需要将两个不同属性的参量绘制在同一张图上&#xff0c;但是两个参量属性不同&#xff0c;即单位不同&#xff0c;纵坐标值分布范围不同&#xff0c;此刻&#xff0c;我们只需要将一个参量的值在y轴左侧展示&#xff0c;另一个参量的值在…

centos7安装mongodb

1、下载mongodb https://www.mongodb.com/try/download/community 2、解压 3、重命名 4、创建mongodb的data、logs目录 5、启动mongodb, bin/mongod --port27017 --dbpath/data/program/mongodb/data --logpath/data/program/mongodb/logs/mongodb.log --bind_ip0.0.0.0 --f…

实用篇-ES-DSL查询文档

数据的存储不是目的&#xff0c;我们希望从海量的酒店数据中检索出需要的信息&#xff0c;这就是ES的搜索功能 官方文档: https://elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html#query-dsl。DSL是用来查询文档的 Elasticsearch提供了基于JSON的DSL来定…

算法通关村——数字中的统计、溢出、进制转换处理模板

数字与数学基础问题 1、数字统计 1.1、符号统计 LeetCode1822. 给定一个数组&#xff0c;求所有元素的乘积的符号&#xff0c;如果最终答案是负的返回-1&#xff0c;如果最终答案是正的返回1&#xff0c;如果答案是0返回0. 这题其实只用看数组中0和负数的个数就好了&#x…

力扣刷题篇之位运算

系列文章目录 目录 系列文章目录 前言 一、位运算的基本运算 二、位运算的技巧 三、布隆过滤器 总结 前言 本系列是个人力扣刷题汇总&#xff0c;本文是数与位。刷题顺序按照[力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 - 力扣&#xff08;LeetCode&#xff0…

DeepMind发布新模型Mirasol3B:更高效处理音频、视频数据

Google DeepMind日前悄然宣布了其人工智能研究的重大进展&#xff0c;推出了一款名为“Mirasol3B”的新型自回归模型&#xff0c;旨在提升对长视频输入的理解能力。该新模型展示了一种颠覆性的多模态学习方法&#xff0c;以更综合和高效的方式处理音频、视频和文本数据。 Googl…

基于STC12C5A60S2系列1T 8051单片机的SPI总线器件数模芯片TLC5615实现数模转换应用

基于STC12C5A60S2系列1T 8051单片的SPI总线器件数模芯片TLC5615实现数模转换应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍SPI总线器件数模芯片TLC5615介绍通过按…

神辅助 Cursor 编辑器,加入 GPT-4 让编码更轻松!

分类 互联网 在 ChatGPT 问世之前&#xff0c;我们的编码方式很多时候都是面向搜索引擎编码&#xff0c;需要不断地进行搜索&#xff0c;然后复制粘贴&#xff0c;俗称复制粘贴工程师。 但是&#xff0c;随着ChatGPT的出现&#xff0c;这一切将彻底改变。 ChatGPT 是一种基于…

nacos网关

目录 拉取docker镜像 环境配置 网关搭建架构 wemedia-gateway网关配置 依赖 启动类配置 网关yml配置 nacos配置中心配置网关 wdmedia服务配置 依赖 启动类配置 yml配置 nacos配置 nacos中的配置共享 nacos配置 wmedia模块中yml的配置 参考:https://blog.csdn.net/…