Flutter文件选择插件file_picker_cross的使用
Flutter文件选择插件file_picker_cross的使用
file_picker_cross
插件允许你在Android、iOS、桌面端(使用go-flutter或FDE)和Web上选择、打开、编辑、保存文档、图片、视频或其他类型的文件。它为读取、写入、将文件作为字符串、字节列表或HTTP上传提供了统一的接口。
开始使用
首先,确保你已经在你的项目中添加了file_picker_cross
依赖项。在你的pubspec.yaml
文件中添加以下依赖:
dependencies:
file_picker_cross: ^版本号
然后运行flutter pub get
来获取新的依赖项。
示例代码
以下是一个完整的示例代码,展示了如何使用file_picker_cross
插件进行文件选择、保存和分享操作。
import 'package:file_picker_cross/file_picker_cross.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final GlobalKey exportKey = GlobalKey();
FilePickerCross? filePickerCross;
String _fileString = '';
Set<String?>? lastFiles;
FileQuotaCross quota = FileQuotaCross(quota: 0, usage: 0);
@override
void initState() {
FilePickerCross.listInternalFiles()
.then((value) => setState(() => lastFiles = value.toSet()));
FilePickerCross.quota().then((value) => setState(() => quota = value));
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSwatch().copyWith(
primary: Colors.blueGrey, secondary: Colors.lightGreen)),
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: ListView(
padding: const EdgeInsets.all(8),
children: <Widget>[
Text(
'Last files',
style: Theme.of(context).textTheme.headline5,
),
(lastFiles == null)
? const Center(
child: CircularProgressIndicator(),
)
: ListView.builder(
shrinkWrap: true,
primary: false,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => ListTile(
leading: Text('$index.'),
title: Text(lastFiles!.toList()[index]!),
onTap: () async => setFilePicker(
await FilePickerCross.fromInternalPath(
path: lastFiles!.toList()[index]!)),
),
itemCount: lastFiles!.length,
),
Builder(
builder: (context) => ElevatedButton(
onPressed: () => _selectFile(context),
child: const Text('Open File...'),
),
),
(filePickerCross == null)
? const Text('Open a file first, to save')
: ElevatedButton(
key: exportKey,
onPressed: _selectSaveFile,
child: const Text('Save as...'),
),
Text(
'File system details',
style: Theme.of(context).textTheme.headline5,
),
Text('Quota: ${(quota.quota / 1e6).round()} MB'),
Text(
'Usage: ${(quota.usage / 1e6).round()}; Remaining: ${(quota.remaining / 1e6).round()}'),
Text('Percentage: ${quota.relative.roundToDouble()}'),
Text(
'File details',
style: Theme.of(context).textTheme.headline5,
),
Text(
'File path: ${filePickerCross?.path ?? 'unknown'} (Might cause issues on web)\n'),
Text('File length: ${filePickerCross?.length ?? 0}\n'),
Text('File as String: $_fileString\n'),
],
),
),
);
}
void _selectFile(context) {
FilePickerCross.importMultipleFromStorage().then((filePicker) {
setFilePicker(filePicker[0]);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('You selected ${filePicker.length} file(s).'),
),
);
setState(() {});
});
}
void _selectSaveFile() {
RenderBox renderBox =
exportKey.currentContext!.findRenderObject() as RenderBox;
Offset position = renderBox.localToGlobal(Offset.zero);
filePickerCross!.exportToStorage(
subject: filePickerCross!.fileName,
sharePositionOrigin: Rect.fromLTWH(
//
position.dx,
position.dy,
renderBox.size.width,
renderBox.size.height));
}
setFilePicker(FilePickerCross filePicker) => setState(() {
filePickerCross = filePicker;
filePickerCross!.saveToPath(path: filePickerCross!.fileName!);
FilePickerCross.quota().then((value) {
setState(() => quota = value);
});
lastFiles!.add(filePickerCross!.fileName);
try {
_fileString = filePickerCross.toString();
} catch (e) {
_fileString = 'Not a text file. Showing base64.\n\n' +
filePickerCross!.toBase64();
}
});
}
异常处理
不同的平台可能会抛出不同的异常,这可能是由于用户操作或平台限制引起的。例如,你可能想了解用户是否拒绝访问存储权限并据此采取行动。为此,你可以使用以下方法:
await FilePickerCross.importFromStorage().then(() {
// ...
}).onError((error, _) {
String _exceptionData = error.reason();
print('----------------------');
print('REASON: ${_exceptionData}');
if (_exceptionData == 'read_external_storage_denied') {
print('Permission was denied');
} else if (_exceptionData == 'selection_canceled') {
print('User canceled operation');
}
print('----------------------');
});
当抛出FileSelectionCanceledError
异常时,你可以通过调用reason()
方法来收集底层异常信息。该方法返回一个String
类型的结果。
文件存储位置
有两个重要的方法用于导出/保存文件:exportToStorage
和 saveToPath
。
exportToStorage
显示一个对话框,允许用户选择保存文件的位置。saveToPath
适用于自动化保存的情况,即应用程序自动创建文件以供后续在应用内部使用。对于Web平台,这意味着文件存储在localStorage中;在Windows平台上,路径是%LOCALAPPDATA%\your_app_name\
;在其他平台上,文件存储在${getApplicationDocumentsDirectory()}/your_app_name/
。
目录选择
目前,移动设备和Web设备的安全机制不允许直接选择目录。不过,你可以使用以下方法来保存文件到指定路径:
// 保存文件到指定路径
filePickerCross.saveToPath('/my/awesome/folder/' + filePickerCross.fileName);
如果你需要在桌面端选择一次目录,并持续保存和读取文件,可以使用以下方法:
// 第一次选择文件时显示导出对话框
FilePickerCross myFile = ...;
String pathForExports = await myFile.exportToStorage(); // <- 将返回文件的路径(仅限桌面端)
// 解析文件的目录并用于后续的自动导出
pathForExports = pathForExports.substring(0, pathForExports.lastIndexOf(r'/'));
print(pathForExports);
// 然后保存路径以便后续使用
...
// 下次检查是否覆盖现有文件或只是写入文件
print(await File(pathForExports + '/myNextFile.csv').exists());
File myCsvFile = await File(pathForExports + '/myNextFile.csv').writeAsString('comma,separated,values'); // <- 这只在桌面端有效,其他设备会阻止此操作。
更多关于Flutter文件选择插件file_picker_cross的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
1 回复