diff --git a/CHANGELOG.md b/CHANGELOG.md index afb4c7b..ee4678c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 2.1.0 +Adds `withReadStream` that allows bigger files to be streamed read into a `Stream>`. 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. diff --git a/lib/src/file_picker.dart b/lib/src/file_picker.dart index cd16d75..2ab97a1 100644 --- a/lib/src/file_picker.dart +++ b/lib/src/file_picker.dart @@ -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>] + /// 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.'); diff --git a/lib/src/file_picker_io.dart b/lib/src/file_picker_io.dart index 0d3dfbd..11d170e 100644 --- a/lib/src/file_picker_io.dart +++ b/lib/src/file_picker_io.dart @@ -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 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 platformFiles = []; + + 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; diff --git a/lib/src/file_picker_web.dart b/lib/src/file_picker_web.dart index 7840438..5d3a8db 100644 --- a/lib/src/file_picker_web.dart +++ b/lib/src/file_picker_web.dart @@ -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> filesCompleter = Completer>(); @@ -63,12 +66,18 @@ class FilePickerWeb extends FilePicker { final List files = uploadInput.files; final List pickedFiles = []; - void addPickedFile(File file, Uint8List bytes, String path) { + void addPickedFile( + File file, + Uint8List bytes, + String path, + Stream> 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> _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; + } + } } diff --git a/lib/src/platform_file.dart b/lib/src/platform_file.dart index 86bcb51..e8d1f71 100644 --- a/lib/src/platform_file.dart +++ b/lib/src/platform_file.dart @@ -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> readStream; + /// The file size in KB. final int size; diff --git a/pubspec.yaml b/pubspec.yaml index 85a8d4c..b46bd0b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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: