Awesome Flutter package that allows you to use the native file explorer to pick single or multiple files, flutter_file_picker
Contents
Introduction
A package is a namespace that holds a collection of classes, interfaces, and sub-packages that are all of the same kind. Packages might be compared to different folders on our computers, where we might have videos in one, photographs in another, software in yet another, and so on. Dart organizes and shares a set of functionality through packages in Flutter. Flutter always supports shared packages, which are provided to the Flutter and Dart ecosystem by other developers. The packages enable us to create the app without having to start from scratch.
File Picker
A package that allows you to use the native file explorer to pick single or multiple files, with extensions filtering support.
Currently supported features
- Uses OS default native pickers
- Supports multiple platforms (Mobile, Web, Desktop and Flutter GO)
- Pick files using custom format filtering — you can provide a list of file extensions (pdf, svg, zip, etc.)
- Pick files from cloud files (GDrive, Dropbox, iCloud)
- Single or multiple file picks
- Different default type filtering (media, image, video, audio or any)
- Picking directories
- Load file data immediately into memory (
Uint8List
) if needed; - Open a save-file / save-as dialog (a dialog that lets the user specify the drive, directory, and name of a file to save)
If you have any feature that you want to see in this package, please feel free to issue a suggestion.
Documentation
See the File Picker Wiki for every detail on about how to install, setup and use it.
Usage
Quick simple usage example:
Single file
FilePickerResult? result = await FilePicker.platform.pickFiles(); if (result != null) { File file = File(result.files.single.path); } else { // User canceled the picker }
Multiple files
FilePickerResult? result = await FilePicker.platform.pickFiles(allowMultiple: true); if (result != null) { List<File> files = result.paths.map((path) => File(path)).toList(); } else { // User canceled the picker }
Multiple files with extension filter
FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom, allowedExtensions: ['jpg', 'pdf', 'doc'], );
Pick a directory
String? selectedDirectory = await FilePicker.platform.getDirectoryPath(); if (selectedDirectory == null) { // User canceled the picker }
Save-file / save-as dialog
String? outputFile = await FilePicker.platform.saveFile( dialogTitle: 'Please select an output file:', fileName: 'output-file.pdf', ); if (outputFile == null) { // User canceled the picker }
Load result and file details
FilePickerResult? result = await FilePicker.platform.pickFiles(); if (result != null) { PlatformFile file = result.files.first; print(file.name); print(file.bytes); print(file.size); print(file.extension); print(file.path); } else { // User canceled the picker }
Pick and upload a file to Firebase Storage with Flutter Web
FilePickerResult? result = await FilePicker.platform.pickFiles(); if (result != null) { Uint8List fileBytes = result.files.first.bytes; String fileName = result.files.first.name; // Upload file await FirebaseStorage.instance.ref('uploads/$fileName').putData(fileBytes); }
For full usage details refer to the Wiki above.
Example Code
Demonstrates how to use the flutter_file_picker.
- Create a flutter app, using flutter command: flutter create app file_picker. Here file_picker being the name of the app.
- In the lib folder is where we store all our .dart codes.
- Create files main.dart, generated_plugin_registrant.dart and main_desktop.dart.
- Create src folder in lib itself.
- Create files inside the above folders as given below:
- main.dart
import 'package:file_picker_example/src/file_picker_demo.dart';
import 'package:flutter/widgets.dart';
void main() => runApp(FilePickerDemo());
- generated_plugin_registrant.dart
//
// Generated file. Do not edit.
//
// ignore_for_file: directives_ordering
// ignore_for_file: lines_longer_than_80_chars
import 'package:file_picker/_internal/file_picker_web.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
// ignore: public_member_api_docs
void registerPlugins(Registrar registrar) {
FilePickerWeb.registerWith(registrar);
registrar.registerMessageHandler();
}
- main_desktop.dart
import 'package:file_picker_example/src/file_picker_demo.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
void main() {
debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
runApp(FilePickerDemo());
}
- src / file_picker_demo.dart
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class FilePickerDemo extends StatefulWidget {
@override
_FilePickerDemoState createState() => _FilePickerDemoState();
}
class _FilePickerDemoState extends State<FilePickerDemo> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final _scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
String? _fileName;
String? _saveAsFileName;
List<PlatformFile>? _paths;
String? _directoryPath;
String? _extension;
bool _isLoading = false;
bool _userAborted = false;
bool _multiPick = false;
FileType _pickingType = FileType.any;
TextEditingController _controller = TextEditingController();
@override
void initState() {
super.initState();
_controller.addListener(() => _extension = _controller.text);
}
void _pickFiles() async {
_resetState();
try {
_directoryPath = null;
_paths = (await FilePicker.platform.pickFiles(
type: _pickingType,
allowMultiple: _multiPick,
onFileLoading: (FilePickerStatus status) => print(status),
allowedExtensions: (_extension?.isNotEmpty ?? false)
? _extension?.replaceAll(' ', '').split(',')
: null,
))
?.files;
} on PlatformException catch (e) {
_logException('Unsupported operation' + e.toString());
} catch (e) {
_logException(e.toString());
}
if (!mounted) return;
setState(() {
_isLoading = false;
_fileName =
_paths != null ? _paths!.map((e) => e.name).toString() : '...';
_userAborted = _paths == null;
});
}
void _clearCachedFiles() async {
_resetState();
try {
bool? result = await FilePicker.platform.clearTemporaryFiles();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: result! ? Colors.green : Colors.red,
content: Text((result
? 'Temporary files removed with success.'
: 'Failed to clean temporary files')),
),
);
} on PlatformException catch (e) {
_logException('Unsupported operation' + e.toString());
} catch (e) {
_logException(e.toString());
} finally {
setState(() => _isLoading = false);
}
}
void _selectFolder() async {
_resetState();
try {
String? path = await FilePicker.platform.getDirectoryPath();
setState(() {
_directoryPath = path;
_userAborted = path == null;
});
} on PlatformException catch (e) {
_logException('Unsupported operation' + e.toString());
} catch (e) {
_logException(e.toString());
} finally {
setState(() => _isLoading = false);
}
}
Future<void> _saveFile() async {
_resetState();
try {
String? fileName = await FilePicker.platform.saveFile(
allowedExtensions: (_extension?.isNotEmpty ?? false)
? _extension?.replaceAll(' ', '').split(',')
: null,
type: _pickingType,
);
setState(() {
_saveAsFileName = fileName;
_userAborted = fileName == null;
});
} on PlatformException catch (e) {
_logException('Unsupported operation' + e.toString());
} catch (e) {
_logException(e.toString());
} finally {
setState(() => _isLoading = false);
}
}
void _logException(String message) {
print(message);
_scaffoldMessengerKey.currentState?.hideCurrentSnackBar();
_scaffoldMessengerKey.currentState?.showSnackBar(
SnackBar(
content: Text(message),
),
);
}
void _resetState() {
if (!mounted) {
return;
}
setState(() {
_isLoading = true;
_directoryPath = null;
_fileName = null;
_paths = null;
_saveAsFileName = null;
_userAborted = false;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
scaffoldMessengerKey: _scaffoldMessengerKey,
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('File Picker example app'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: DropdownButton<FileType>(
hint: const Text('LOAD PATH FROM'),
value: _pickingType,
items: FileType.values
.map((fileType) => DropdownMenuItem<FileType>(
child: Text(fileType.toString()),
value: fileType,
))
.toList(),
onChanged: (value) => setState(() {
_pickingType = value!;
if (_pickingType != FileType.custom) {
_controller.text = _extension = '';
}
})),
),
ConstrainedBox(
constraints: const BoxConstraints.tightFor(width: 100.0),
child: _pickingType == FileType.custom
? TextFormField(
maxLength: 15,
autovalidateMode: AutovalidateMode.always,
controller: _controller,
decoration: InputDecoration(
labelText: 'File extension',
),
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.none,
)
: const SizedBox(),
),
ConstrainedBox(
constraints: const BoxConstraints.tightFor(width: 200.0),
child: SwitchListTile.adaptive(
title: Text(
'Pick multiple files',
textAlign: TextAlign.right,
),
onChanged: (bool value) =>
setState(() => _multiPick = value),
value: _multiPick,
),
),
Padding(
padding: const EdgeInsets.only(top: 50.0, bottom: 20.0),
child: Column(
children: <Widget>[
ElevatedButton(
onPressed: () => _pickFiles(),
child: Text(_multiPick ? 'Pick files' : 'Pick file'),
),
SizedBox(height: 10),
ElevatedButton(
onPressed: () => _selectFolder(),
child: const Text('Pick folder'),
),
SizedBox(height: 10),
ElevatedButton(
onPressed: () => _saveFile(),
child: const Text('Save file'),
),
SizedBox(height: 10),
ElevatedButton(
onPressed: () => _clearCachedFiles(),
child: const Text('Clear temporary files'),
),
],
),
),
Builder(
builder: (BuildContext context) => _isLoading
? Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: const CircularProgressIndicator(),
)
: _userAborted
? Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: const Text(
'User has aborted the dialog',
),
)
: _directoryPath != null
? ListTile(
title: const Text('Directory path'),
subtitle: Text(_directoryPath!),
)
: _paths != null
? Container(
padding:
const EdgeInsets.only(bottom: 30.0),
height:
MediaQuery.of(context).size.height *
0.50,
child: Scrollbar(
child: ListView.separated(
itemCount: _paths != null &&
_paths!.isNotEmpty
? _paths!.length
: 1,
itemBuilder: (BuildContext context,
int index) {
final bool isMultiPath =
_paths != null &&
_paths!.isNotEmpty;
final String name =
'File $index: ' +
(isMultiPath
? _paths!
.map((e) => e.name)
.toList()[index]
: _fileName ?? '...');
final path = kIsWeb
? null
: _paths!
.map((e) => e.path)
.toList()[index]
.toString();
return ListTile(
title: Text(
name,
),
subtitle: Text(path ?? ''),
);
},
separatorBuilder:
(BuildContext context,
int index) =>
const Divider(),
)),
)
: _saveAsFileName != null
? ListTile(
title: const Text('Save file'),
subtitle: Text(_saveAsFileName!),
)
: const SizedBox(),
),
],
),
),
),
),
),
);
}
}
Example App
Android
iOS
MacOS
Linux
Windows
Getting Started
For help getting started with Flutter, view our online documentation.
For help on editing plugin code, view the documentation.