在颤抖中,rootBundle.load()
给了我一个ByteData
对象。
dart中的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;
}
答案 0 :(得分:2)
在Dart中,ByteData
与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;
}
答案 1 :(得分:2)
如果您正在做的工作很昂贵并且不想阻塞UI,请使用package:flutter/foundation.dart
中的compute
方法。这将在单独的隔离中运行提供的函数,并异步将结果返回给您。 loadEncryptedPdf
必须是顶级函数或静态函数才能在此处使用,而且您只能传递一个参数(但可以将它们放在Map中)。
import 'package:flutter/foundation.dart';
Future<String> loadEncryptedPdf(Map<String, String> arguments) async {
// this runs on another isolate
...
}
final String result = await compute(loadEncryptedPdf, {'fileName': /*.../*});
答案 2 :(得分:2)
因此,虽然@Jonah Williams和@Richard Heap所发布的答案不能单独满足,但我尝试将两者结合使用,对我很有用。
这是一个完整的解决方案-
使用path_provider软件包获取缓存目录
import 'package:flutter/foundation.dart';
import 'package:path_provider/path_provider.dart';
// Holds a Future to a temporary cache directory
final cacheDirFuture =
(() async => (await (await getTemporaryDirectory()).createTemp()).path)();
_xorDecryptIsolate(args) {
Uint8List pdfBytes = args[0].buffer.asUint8List();
String secretKey = args[1];
File outputFile = args[2];
int lenSecretKey = secretKey.length;
for (int i = 0; i < pdfBytes.length; i++)
pdfBytes[i] ^= secretKey.codeUnitAt(i % lenSecretKey);
outputFile.writeAsBytesSync(pdfBytes, flush: true);
}
/// decrypt a file from assets using XOR,
/// and return the path to a cached-temporary decrypted file.
xorDecryptFromAssets(String assetFileName, String secretKey) async {
final pdfBytesData = await rootBundle.load('assets/$assetFileName');
final outputFilePath = (await pdfCacheDirFuture) + '/' + assetFileName;
final outputFile = File(outputFilePath);
if ((await outputFile.stat()).size > 0) {
print('decrypting $assetFileName using $secretKey ..');
await compute(_xorDecryptIsolate, [pdfBytesData, secretKey, outputFile]);
print('done!');
}
return outputFilePath;
}