首页 > 解决方案 > Flutter:如何在不阻塞 UI 的情况下异步地从资产中读取文件

问题描述

在颤动中,rootBundle.load()给了我一个ByteData对象。

ByteData飞镖中的对象到底是什么?它可以用于异步读取文件吗?

我真的不明白这背后的动机。

为什么不给我一个好的File对象,或者更好的是资产的完整路径?

就我而言,我想从资产文件中异步读取字节,逐字节地写入新文件。(构建一个不会挂断 UI 的 XOR 解密的东西)

这是我能做的最好的事情,它悲惨地挂断了 UI。

loadEncryptedPdf(fileName, secretKey, cacheDir) async {
  final lenSecretKey = secretKey.length;

  final encryptedByteData = await rootBundle.load('assets/$fileName');

  final outputFilePath = cacheDir + '/' + fileName;
  final outputFile = File(outputFilePath);

  if (!await outputFile.exists()) {
    Stream decrypter() async* {
      // read bits from encryptedByteData, and stream the xor inverted bits

      for (var index = 0; index < encryptedByteData.lengthInBytes; index++)
        yield encryptedByteData.getUint8(index) ^
        secretKey.codeUnitAt(index % lenSecretKey);
      print('done!');
    }

    print('decrypting $fileName using $secretKey ..');
    await outputFile.openWrite(encoding: AsciiCodec()).addStream(decrypter());
    print('finished');
  }

  return outputFilePath;
}

标签: asynchronousfile-iodartflutter

解决方案


在 Dart 中 aByteData类似于 Java ByteBuffer。它包装了一个字节数组,为 1、2 和 4 字节整数(两种字节序)提供 getter 和 setter 函数。

由于您要操作字节,因此最简单的方法是处理底层字节数组( Dart Uint8List)。RootBundle.load()已经将整个资产读入内存,因此在内存中更改并写出。

Future<String> loadEncryptedPdf(
    String fileName, String secretKey, String cacheDir) async {
  final lenSecretKey = secretKey.length;

  final encryptedByteData = await rootBundle.load('assets/$fileName');

  String path = cacheDir + '/' + fileName;
  final outputFile = File(path);

  if (!await outputFile.exists()) {
    print('decrypting $fileName using $secretKey ..');

    Uint8List bytes = encryptedByteData.buffer.asUint8List();
    for (int i = 0; i < bytes.length; i++) {
      bytes[i] ^= secretKey.codeUnitAt(i % lenSecretKey);
    }

    await outputFile.writeAsBytes(bytes);
    print('finished');
  }

  return path;
}

推荐阅读