dart 中不可避免會出現文件讀取的情況, 甚至是很大的文件, 比如 200M 的文件
如果一次性讀入內存,雖然也行得通, 但是如果在 flutter 中開啟個 200M 大小的字節數組, 一不小心可能就 crash 了, 這時候就需要使用大文件讀取的方案
讀取文件
核心方法:
file.openRead();
這個方法可以指定開始和結束的坐標, 並開啟一個 stream
stream
回調信息是 List<int>
,單次最大讀取 65536
個字節
示例
class FileUtils {
File file;
FileUtils(this.file);
// 讀取文件的某個范圍返回
Future<List<int>> getRange(int start, int end) async {
if (file == null || !file.existsSync()) {
throw FileNotExistsError();
}
if (start < 0) {
throw RangeError.range(start, 0, file.lengthSync());
}
if (end > file.lengthSync()) {
throw RangeError.range(end, 0, file.lengthSync());
}
final c = MyCompleter<List<int>>();
List<int> result = [];
file.openRead(start, end).listen((data) {
result.addAll(data);
}).onDone(() {
c.reply(result);
});
return c.future;
}
}
用到的 completer
在這里
import 'dart:async';
class MyCompleter<T> {
Completer<T> completer = Completer();
MyCompleter();
Future<T> get future => completer.future;
void reply(T result) {
if (!completer.isCompleted) {
completer.complete(result);
}
}
}
這里主要是封裝了一個指定某個范圍返回的方法, 比如我寫了一個簡單的 dart 包, 通過讀取元數據的方案, 來讀取圖片大小, 這樣不用通過完整的解碼即可完成, 效率比 dart:ui.Image 解碼后查看寬高要高的多
項目地址: https://github.com/CaiJingLong/dart_image_size_getter
比如判斷一個文件是不是 jpeg 格式, 需要判斷開頭兩個字節和結尾兩個字節是不是 0xFF 0xD9 開頭, 0xFF 0xD8 結尾
原始代碼是這樣的, 很不清晰, 也比較難以閱讀:
經過修改后是這樣的
static Future<bool> isJpg(File file) async {
if (file == null || !file.existsSync()) {
return false;
}
const start = [0xFF, 0xD9];
const end = [0xFF, 0xD8];
final completer = MyCompleter<bool>();
void foo() async {
final util = FileUtils(file);
final length = file.lengthSync();
final startList = await util.getRange(0, 2);
final endList = await util.getRange(length - 2, length);
const eq = ListEquality();
completer.reply(eq.equals(start, startList) && eq.equals(end, endList));
}
foo();
return completer.future;
}
后記
項目地址: https://github.com/CaiJingLong/dart_image_size_getter
pub get
dart bin/main.dart
以上