Dev*_*wal 5 file-io asynchronous dart flutter
在颤动中,rootBundle.load()给了我一个ByteData对象。
到底什么是ByteData?可以用来异步读取文件吗?
我真的不明白这背后的动机。
为什么不给我一个好的ol'File,或者更好的是资产的完整路径?
就我而言,我想从资产文件中异步读取字节,逐字节并写入新文件。(构建一个不会挂起 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;
}
Run Code Online (Sandbox Code Playgroud)
在 Dart 中 aByteData类似于 JavaByteBuffer。它包装了一个字节数组,为 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;
}
Run Code Online (Sandbox Code Playgroud)
因此,虽然@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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8817 次 |
| 最近记录: |