Flutter当前目录隔离插件isolate_current_directory的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter当前目录隔离插件isolate_current_directory的使用

标题

isolate_current_directory

描述

此库导出一个函数 withCurrentDirectory,可以在lambda的作用域内更改 Directory.current(工作目录),但不会改变全局值。

这意味着使用此函数,可以编写并发Dart代码,在不同的工作目录中执行而不会相互影响。

使用此库

要添加依赖项,请在pubspec.yaml文件中添加:

dart pub add isolate_current_directory

现在,您可以使用 withCurrentDirectory

withCurrentDirectory('my-dir', () async {
  // 这个文件位于 my-dir/example.txt
  final file = File('example.txt');
  // 使用这个文件!
});

请参阅 isolate_current_directory_example.dart 以获取完整的示例。

动机

Dart的 Directory.current 是一个全局变量,可以在任何时候由任何Dart代码更改。

在异步代码中,您可以通过使用 synchronized 包中的锁来尝试避免在其他异步代码运行时修改工作目录,但这不可能保证,因为任何忽略锁的代码仍然可能同时修改工作目录。

这个问题在存在 Isolate 的的情况下更加棘手,因为如果任何 Isolate 中的代码更改了工作目录,那么所有其他 Isolate 都会看到这一点,但没有我知道的方法来同步对 Directory.current 的访问,因为 Isolate 应该彼此隔离,因此它们不能共享同一个锁!

通过使用 IOOverrides,此库利用Dart的 Zone 来隔离 Directory.current 到函数的作用域。无论有多少个函数并发运行,甚至跨越多个 Isolate,每个函数都有自己的工作目录。它可以更改自己的工作目录而不影响其他在不同作用域中运行的代码。

注意事项

  • 进程:不幸的是,Process 方法默认不尊重被限制的工作目录值。
  • Isolates:当启动新的 Isolate 时,新 Isolate 不会继承调用代码的受限当前目录。
  • 性能:当在 withCurrentDirectory 的作用域内创建 FileSystemEntity 时,会创建自定义的 dart:io 类型(如 FileDirectoryLink),每次操作都会检查当前的值,这可能会在应用程序的热点路径上产生非可忽略的成本。
  • 链接:链接大多正常工作,但神秘地,exists() 看起来不起作用。

示例代码

import 'dart:io';

import 'package:isolate_current_directory/isolate_current_directory.dart';

void main() {
  withCurrentDirectory('lib', () async {
    // File 和 Directory 创建在 "withCurrentDirectory" 内部
    // 将使用 'lib' 作为工作目录。
    final src = Directory('src');
    print('Directory src exists? ${await src.exists()}');
    await src.list(recursive: true).forEach((child) => print(' * $child'));

    // 但是 Process 方法目前不尊重 Directory.current,
    // 因此必须显式提供工作目录。
    final ls = await Process.run('ls', const [],
        workingDirectory: Directory.current.path);
    print('Result of running "ls" at ${Directory.current}');
    stdout.write(ls.stdout);
    stderr.write(ls.stderr);
  });
}

更多关于Flutter当前目录隔离插件isolate_current_directory的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter当前目录隔离插件isolate_current_directory的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于Flutter中的isolate_current_directory插件的使用,这里是一个具体的代码案例,展示了如何在一个Flutter应用中利用这个插件来实现当前目录隔离(Isolate Current Directory)的功能。

首先,确保你已经在pubspec.yaml文件中添加了isolate_current_directory依赖:

dependencies:
  flutter:
    sdk: flutter
  isolate_current_directory: ^最新版本号 # 请替换为实际的最新版本号

然后,运行flutter pub get来安装依赖。

接下来,在你的Flutter应用中,你可以按照以下步骤使用isolate_current_directory插件:

  1. 导入插件

在你的Dart文件中导入插件:

import 'package:isolate_current_directory/isolate_current_directory.dart';
  1. 使用Isolate运行代码并隔离当前目录

下面是一个完整的示例,展示了如何在Isolate中运行代码,并确保Isolate有其自己的工作目录:

import 'package:flutter/material.dart';
import 'package:isolate_current_directory/isolate_current_directory.dart';
import 'dart:isolate';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Isolate Current Directory Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              // 定义一个在Isolate中运行的函数
              void isolateFunction(SendPort sendPort) {
                // 获取Isolate的当前工作目录
                String currentDir = Directory.current.path;
                // 通过SendPort发送结果回主Isolate
                sendPort.send(currentDir);
              }

              // 创建ReceivePort来接收来自Isolate的消息
              final ReceivePort receivePort = ReceivePort();
              // 使用isolate_current_directory插件启动Isolate
              await Isolate.spawnFunction(
                isolateFunctionWrapper(isolateFunction, receivePort.sendPort),
                // 这里可以传递需要给Isolate的额外数据(如果有的话)
                null,
                // 使用插件的onIsolateStart回调来隔离当前目录
                onIsolateStart: (Isolate isolate) async {
                  await isolate_current_directory.isolateCurrentDirectory(isolate);
                },
              );

              // 从ReceivePort接收Isolate发送的消息
              String isolateCurrentDir = await receivePort.first;
              print('Isolate中的当前目录: $isolateCurrentDir');
            },
            child: Text('启动Isolate并获取其当前目录'),
          ),
        ),
      ),
    );
  }
}

// 辅助函数:包装isolateFunction,使其符合Isolate.spawnFunction的参数要求
typedef IsolateFunctionWrapper = void Function(SendPort sendPort);
IsolateFunctionWrapper isolateFunctionWrapper(
    void Function(SendPort sendPort) func, SendPort sendPort) {
  return (SendPort replyTo) {
    func(sendPort);
  };
}

在这个示例中,我们创建了一个Flutter应用,其中包含一个按钮。点击按钮时,将启动一个新的Isolate,并使用isolate_current_directory插件来隔离其当前工作目录。Isolate运行一个函数,该函数获取其当前工作目录并通过SendPort发送回主Isolate。主Isolate接收并打印这个目录路径。

注意:

  • isolate_current_directory插件的isolateCurrentDirectory函数确保Isolate有其自己的工作目录,这是通过修改Dart VM的内部机制来实现的。
  • 由于Isolate的工作方式,确保你理解Dart中的并发编程和Isolate间的通信机制是很重要的。

希望这个示例能帮助你理解如何在Flutter应用中使用isolate_current_directory插件!

回到顶部