Added withReadStream option to load a file in chunks (useful for large files)

This commit is contained in:
redsolver 2020-11-12 18:28:57 +01:00 committed by Miguel Ruivo
parent d2d4de7bf8
commit 2aafd1131c
6 changed files with 66 additions and 8 deletions

View File

@ -1,3 +1,6 @@
## 2.1.0
Adds `withReadStream` that allows bigger files to be streamed read into a `Stream<List<int>>`. Thanks @redsolver.
## 2.0.13
Updates `extension` helper getter to use the `name` property instead of `path`, since the latest isn't available on the Web, hence, the extension wouldn't be as well. Thank you @markgrancapal.

View File

@ -49,6 +49,9 @@ abstract class FilePicker extends PlatformInterface {
/// If [withData] is set, picked files will have its byte data immediately available on memory as [Uint8List]
/// which can be useful if you are picking it for server upload or similar.
///
/// If [withReadStream] is set, picked files will have its byte data available as a [Stream<List<int>>]
/// which can be useful for uploading and processing large files.
///
/// If you want to track picking status, for example, because some files may take some time to be
/// cached (particularly those picked from cloud providers), you may want to set [onFileLoading] handler
/// that will give you the current status of picking.
@ -64,6 +67,7 @@ abstract class FilePicker extends PlatformInterface {
bool allowCompression,
bool allowMultiple = false,
bool withData,
bool withReadStream,
}) async =>
throw UnimplementedError('pickFiles() has not been implemented.');

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:file_picker/src/platform_file.dart';
@ -25,6 +26,7 @@ class FilePickerIO extends FilePicker {
bool allowCompression = true,
bool allowMultiple = false,
bool withData = false,
bool withReadStream = false,
}) =>
_getPath(
type,
@ -33,6 +35,7 @@ class FilePickerIO extends FilePicker {
allowedExtensions,
onFileLoading,
withData,
withReadStream,
);
@override
@ -59,6 +62,7 @@ class FilePickerIO extends FilePicker {
List<String> allowedExtensions,
Function(FilePickerStatus) onFileLoading,
bool withData,
bool withReadStream,
) async {
final String type = describeEnum(fileType);
if (type != 'custom' && (allowedExtensions?.isNotEmpty ?? false)) {
@ -87,8 +91,20 @@ class FilePickerIO extends FilePicker {
return null;
}
return FilePickerResult(
result.map((file) => PlatformFile.fromMap(file)).toList());
final List<PlatformFile> platformFiles = <PlatformFile>[];
for (final platformFileMap in result) {
platformFiles.add(
PlatformFile.fromMap(
platformFileMap,
readStream: withReadStream
? File(platformFileMap['path']).openRead()
: null,
),
);
}
return FilePickerResult(platformFiles);
} on PlatformException catch (e) {
print('[$_tag] Platform exception: $e');
rethrow;

View File

@ -12,6 +12,8 @@ class FilePickerWeb extends FilePicker {
Element _target;
final String _kFilePickerInputsDomId = '__file_picker_web-file-input';
final int _readStreamChunkSize = 1000 * 1000; // 1 MB
static final FilePickerWeb platform = FilePickerWeb._();
FilePickerWeb._() {
@ -43,6 +45,7 @@ class FilePickerWeb extends FilePicker {
Function(FilePickerStatus) onFileLoading,
bool allowCompression,
bool withData = true,
bool withReadStream = false,
}) async {
final Completer<List<PlatformFile>> filesCompleter =
Completer<List<PlatformFile>>();
@ -63,12 +66,18 @@ class FilePickerWeb extends FilePicker {
final List<File> files = uploadInput.files;
final List<PlatformFile> pickedFiles = [];
void addPickedFile(File file, Uint8List bytes, String path) {
void addPickedFile(
File file,
Uint8List bytes,
String path,
Stream<List<int>> readStream,
) {
pickedFiles.add(PlatformFile(
name: file.name,
path: path,
size: bytes != null ? bytes.length ~/ 1024 : -1,
size: bytes != null ? bytes.length ~/ 1024 : file.size,
bytes: bytes,
readStream: readStream,
));
if (pickedFiles.length >= files.length) {
@ -77,10 +86,15 @@ class FilePickerWeb extends FilePicker {
}
files.forEach((File file) {
if (withReadStream) {
addPickedFile(file, null, null, _openFileReadStream(file));
return;
}
if (!withData) {
final FileReader reader = FileReader();
reader.onLoadEnd.listen((e) {
addPickedFile(file, null, reader.result);
addPickedFile(file, null, reader.result, null);
});
reader.readAsDataUrl(file);
return;
@ -88,7 +102,7 @@ class FilePickerWeb extends FilePicker {
final FileReader reader = FileReader();
reader.onLoadEnd.listen((e) {
addPickedFile(file, reader.result, null);
addPickedFile(file, reader.result, null, null);
});
reader.readAsArrayBuffer(file);
});
@ -129,4 +143,20 @@ class FilePickerWeb extends FilePicker {
}
return '';
}
Stream<List<int>> _openFileReadStream(File file) async* {
final reader = FileReader();
int start = 0;
while (start < file.size) {
final end = start + _readStreamChunkSize > file.size
? file.size
: start + _readStreamChunkSize;
final blob = file.slice(start, end);
reader.readAsArrayBuffer(blob);
await reader.onLoad.first;
yield reader.result;
start += _readStreamChunkSize;
}
}
}

View File

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:typed_data';
class PlatformFile {
@ -5,10 +6,11 @@ class PlatformFile {
this.path,
this.name,
this.bytes,
this.readStream,
this.size,
});
PlatformFile.fromMap(Map data)
PlatformFile.fromMap(Map data, {this.readStream})
: this.path = data['path'],
this.name = data['name'],
this.bytes = data['bytes'],
@ -28,6 +30,9 @@ class PlatformFile {
/// or easily upload to somewhere else.
final Uint8List bytes;
/// File content as stream
final Stream<List<int>> readStream;
/// The file size in KB.
final int size;

View File

@ -1,7 +1,7 @@
name: file_picker
description: A package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support.
homepage: https://github.com/miguelpruivo/plugins_flutter_file_picker
version: 2.0.13
version: 2.1.0
dependencies:
flutter: