isolate_current_directory

GitHub Actions pub package

此库导出一个名为 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 类型(FileDirectoryLink)的自定义实现,该实现将在每次操作时检查 Directory.current 的作用域值,如果这种情况发生在应用程序的热路径中,可能会产生不可忽略的成本。

链接 bug

链接大部分有效,但不知何故,exists() 似乎无效。

请参阅 link_test.dart

GitHub

查看 Github