isolate_current_directory
此库导出一个名为 withCurrentDirectory 的函数,该函数可以在 lambda 的作用域内更改 Directory.current(工作目录),但不会更改全局值。
这意味着,通过使用此函数,可以编写并发的 Dart 代码,这些代码在不同的工作目录中执行,而不会相互影响。
使用此库
在 pubspec 中添加依赖项
dart pub add isolate_current_directory
现在,您可以使用 withCurrentDirectory
withCurrentDirectory('my-dir', () async {
// this file resolves to my-dir/example.txt
final file = File('example.txt');
// use the file!
});
有关完整的示例,请参阅 isolate_current_directory_example.dart。
动机
Dart 的 Directory.current 是一个全局变量,可以随时由任何 Dart 代码修改。
在异步代码中,您可以使用锁(请参阅 synchronized 包)来尝试避免在其他异步代码运行时修改工作目录,但这无法保证,因为任何忽略锁的代码仍然可以并发修改工作目录。
这个问题在存在 Isolate 时更加令人头痛,因为如果任何 Isolate 中的任何代码更改了工作目录,那么所有其他 Isolate 都会看到这一点,但据我所知,它们无法同步对 Directory.current 的访问,因为 Isolate 应该彼此隔离,所以它们不能共享同一个锁!
通过使用 IOOverrides,此库利用 Dart 的 Zone 来将 Directory.current 隔离到函数的范围。无论有多少函数并发运行,甚至跨多个 Isolate,每个函数都有自己的工作目录。它可以更改自己的工作目录,而不会影响在不同作用域中运行的任何其他代码。
注意事项
进程
不幸的是,Process 中的方法默认不遵循作用域内的 Directory.current 值。
因此,在使用 Process 时,必须显式传递 workingDirectory 参数
Process.start('cmd', const ['args'], workingDirectory: Directory.current.path);
性能
另一个可能的问题是性能。当在 withCurrentDirectory 的作用域内创建 FileSystemEntity 时,会创建一个 dart:io 类型(File、Directory、Link)的自定义实现,该实现将在每次操作时检查 Directory.current 的作用域值,如果这种情况发生在应用程序的热路径中,可能会产生不可忽略的成本。
链接 bug
链接大部分有效,但不知何故,exists() 似乎无效。
请参阅 link_test.dart。