Asynchronous 颤振:如何从资产中异步读取文件,而不阻塞UI
在flatter中,Asynchronous 颤振:如何从资产中异步读取文件,而不阻塞UI,asynchronous,file-io,dart,flutter,Asynchronous,File Io,Dart,Flutter,在flatter中,rootBundle.load()给我一个ByteData对象 dart中的ByteData对象到底是什么?它可以用来异步读取文件吗 我真的不明白这背后的动机 为什么不给我一个好的ol'文件对象,或者更好的是资产的完整路径 在我的例子中,我希望以异步方式逐字节读取资产文件中的字节,然后写入新文件。(构建一个不会挂断UI的XOR解密工具) 这是我所能做的最好的了,它很糟糕地挂断了用户界面 loadEncryptedPdf(fileName, secretKey, cacheDi
rootBundle.load()
给我一个ByteData
对象
dart中的ByteData
对象到底是什么?它可以用来异步读取文件吗
我真的不明白这背后的动机
为什么不给我一个好的ol'文件
对象,或者更好的是资产的完整路径
在我的例子中,我希望以异步方式逐字节读取资产文件中的字节,然后写入新文件。(构建一个不会挂断UI的XOR解密工具)
这是我所能做的最好的了,它很糟糕地挂断了用户界面
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;
}
loadEncryptedPdf(文件名、secretKey、cacheDir)异步{
最终lenSecretKey=secretKey.length;
final encryptedByteData=wait rootBundle.load('assets/$fileName');
最终输出文件路径=cacheDir+'/'+文件名;
最终输出文件=文件(输出文件路径);
如果(!await outputFile.exists()){
流解密程序()异步*{
//从encryptedByteData读取位,并流式传输异或反转位
对于(var索引=0;索引在Dart中,字节数据与Java字节缓冲类似。它包装一个字节数组,为1、2和4字节整数(都是尾数)提供getter和setter函数
因为您想要操作字节,所以只需操作底层字节数组(DartUint8List
)就很容易了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;
}
Future loadEncryptedPdf(
字符串文件名、字符串secretKey、字符串cacheDir)异步{
最终lenSecretKey=secretKey.length;
final encryptedByteData=wait rootBundle.load('assets/$fileName');
字符串路径=cacheDir+'/'+文件名;
最终输出文件=文件(路径);
如果(!await outputFile.exists()){
打印(“使用$secretKey..解密$fileName”);
Uint8List bytes=encryptedByteData.buffer.asUint8List();
for(int i=0;i
如果您所做的工作非常昂贵,并且您不想阻塞UI,请使用包中的方法:flatter/foundation.dart
。这将在单独的隔离中运行提供的函数,并将结果异步返回给您loadEncryptedPdf
必须是顶级函数或静态函数才能在此处使用,并且只能传递一个参数(但可以将它们放在映射中)
导入“包:flift/foundation.dart”;
Future loadEncryptedPdf(映射参数)异步{
//这在另一个隔离上运行
...
}
最终字符串结果=等待计算(loadEncryptedPdf,{'fileName':/*…/*});
因此,尽管@Jonah Williams和@Richard Heap发布的答案本身并不足够,但我尝试了两者的结合,这对我很有好处
这里有一个完整的解决方案-
使用path_提供程序包获取缓存目录
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;
}
导入“包:flift/foundation.dart”;
导入“package:path_provider/path_provider.dart”;
//保存临时缓存目录的未来
最终的未来=
(()async=>(await(await getTemporaryDirectory()).createTemp()).path)();
_XorderCryptIsolate(args){
Uint8List pdfBytes=args[0]。buffer.asUint8List();
字符串secretKey=args[1];
File outputFile=args[2];
int lenSecretKey=secretKey.length;
对于(int i=0;i0){
打印(“使用$secretKey..解密$assetFileName”);
等待计算(_xorDecryptIsolate,[pdfBytesData,secretKey,outputFile]);
打印('done!');
}
返回outputFilePath;
}
如何获取资产中文件的文件路径?我试图查找getApplicationDocumentsDirectory()
,但它不在那里。甚至尝试将它放入android/app/src/main/assets/
,并使用文件
对象和安卓file:///android_asset/
url,但这只是说文件不存在。。看起来我唯一的选择是现在就编写本机代码..请不要使用outputFile.exists()。更多信息:。这会导致异常:只能从主隔离发送平台消息无法使用隔离从资产读取文件:(
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;
}