openRead method
Implementation
@override
FileReadSession<Uint8List> openRead(
String path, {
int chunkSize = 64 * 1024,
int start = 0,
}) {
if (path.isEmpty) {
throw ArgumentError.value(path, 'path', 'path must not be empty');
}
if (chunkSize <= 0) {
throw ArgumentError.value(
chunkSize,
'chunkSize',
'chunkSize must be greater than zero',
);
}
if (start < 0) {
throw ArgumentError.value(start, 'start', 'start must not be negative');
}
if (!_forceNativeRead &&
(Platform.isMacOS || Platform.isWindows || Platform.isLinux)) {
return _openDesktopRead(path, chunkSize: chunkSize, start: start);
}
StreamSubscription<dynamic>? subscription;
String? streamId;
bool cancelled = false;
bool closed = false;
Future<void>? cancelFuture;
late final StreamController<Uint8List> controller;
late final Future<void> Function() cancelOnce;
controller = StreamController<Uint8List>(
onListen: () async {
try {
streamId = await methodChannel.invokeMethod<String>('startRead', {
'path': path,
'chunkSize': chunkSize,
'start': start,
});
if (streamId == null || streamId!.isEmpty) {
throw PlatformException(
code: 'missing_stream_id',
message: 'Native reader did not return a stream identifier.',
);
}
if (cancelled) {
await _cancelRead(streamId!);
await _closeController(
controller,
alreadyClosed: () => closed,
onClose: () => closed = true,
);
return;
}
subscription = EventChannel('$_readChannelPrefix/$streamId')
.receiveBroadcastStream()
.listen(
(event) {
if (event is Uint8List) {
controller.add(event);
return;
}
if (event is ByteData) {
controller.add(event.buffer.asUint8List());
return;
}
if (event is List && event.every((item) => item is int)) {
controller.add(Uint8List.fromList(event.cast<int>()));
return;
}
controller.addError(
PlatformException(
code: 'invalid_chunk',
message:
'Unexpected native chunk type: ${event.runtimeType}.',
),
);
},
onError: controller.addError,
onDone: () async {
await _closeController(
controller,
alreadyClosed: () => closed,
onClose: () => closed = true,
);
},
);
} catch (error, stackTrace) {
controller.addError(error, stackTrace);
await _closeController(
controller,
alreadyClosed: () => closed,
onClose: () => closed = true,
);
}
},
onPause: () => subscription?.pause(),
onResume: () => subscription?.resume(),
onCancel: () => cancelOnce(),
);
cancelOnce = () {
return cancelFuture ??= () async {
cancelled = true;
await subscription?.cancel();
if (streamId != null && streamId!.isNotEmpty) {
await _cancelRead(streamId!);
}
await _closeController(
controller,
alreadyClosed: () => closed,
onClose: () => closed = true,
);
}();
};
return FileReadSession<Uint8List>(
stream: controller.stream,
onCancel: cancelOnce,
);
}