كما لاحظت في لقطة الشاشة، .txtلا يتم تمييز بعض الملفات، وذلك لأنها ملحقة بـ (1). يحدث هذا إذا كنت تريد حفظ ملفات بنفس الاسم.
إضافة رسائل Snackbar
حتى الآن، قمنا بتنفيذ القدرة على تصدير الملفات، ولكننا لم نقدم بعد أي ملاحظات للمستخدم حول ما إذا كان التصدير ناجحًا أم لا.
import 'dart:convert';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
class FilePickerPage extends StatelessWidget {
const FilePickerPage({super.key});
void _showSnackBar(BuildContext context, Color color, String text) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: color,
content: Center(child: Text(text)),
duration: const Duration(seconds: 2),
),
);
}
Future<void> _exportFile(BuildContext context) async => FilePicker.platform.saveFile(
bytes: utf8.encode('Only Flutter'),
fileName: 'only_flutter.txt',
allowedExtensions: ['txt'],
).then((String? path) {
if (!context.mounted) return;
if (path != null) {
_showSnackBar(context, Colors.green, 'Export successful.');
} else {
_showSnackBar(context, Colors.red, 'Export failed.');
}
});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () async => _exportFile(context),
child: const Text('Export File'),
),
],
),
),
);
}
}
في مقتطف الكود أعلاه، أضفنا _showSnackbarوظيفة لعرض SnackBarالرسائل. ولأننا نريد عرض SnackBarرسائل متعددة، فقد أنشأنا وظيفة لتجنب تكرار الكود.
بعد ذلك، أضفنا thenالدالة لتنفيذ معاودة الاتصال بمجرد اكتمال عملية الإرجاع Futureبواسطة saveFileالدالة. داخل thenالدالة، نتحقق أولاً مما إذا كان السياق مُركَّبًا، ثم نعرض رسالة SnackBar. بناءً على ما إذا كان المسار مُركَّبًا nullأم لا، نعرض إما رسالة حمراء أو خضراء لإظهار ما إذا كان التصدير ناجحًا أم لا.
SnackBarيتم عرض الرسالة الحمراء عند الضغط على زر الرجوع في نظام Android.
استيراد الملفات باستخدام File Picker في Flutter
الآن بعد أن تعرفت على كيفية تصدير الملفات باستخدام أداة اختيار الملفات في Flutter، دعنا ننتقل إلى استيراد الملفات.
import 'dart:convert';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
class FilePickerPage extends StatelessWidget {
const FilePickerPage({super.key});
void _showSnackBar(BuildContext context, Color color, String text) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: color,
content: Center(child: Text(text)),
duration: const Duration(seconds: 2),
),
);
}
Future<void> _exportFile(BuildContext context) async => FilePicker.platform.saveFile(
bytes: utf8.encode('Only Flutter'),
fileName: 'only_flutter.txt',
).then((String? path) {
if (!context.mounted) return;
if (path != null) {
_showSnackBar(context, Colors.green, 'Export successful.');
} else {
_showSnackBar(context, Colors.red, 'Export failed.');
}
});
Future<void> _importFile() async =>
FilePicker.platform.pickFiles().then((FilePickerResult? result) async {
if (result != null) {
final PlatformFile selectedFile = result.files.single;
if (selectedFile.path == null) {
return;
}
final File file = File(selectedFile.path!);
print(await file.readAsString());
}
});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () async => _exportFile(context),
child: const Text('Export File'),
),
ElevatedButton(
onPressed: _importFile,
child: const Text('Import File'),
),
],
),
),
);
}
}
توفر الفئة PlatformFileسمات أكثر من مجرد path. على سبيل المثال، يمكنك أيضًا الوصول إلى name, extension, size, وما إلى ذلك.
فرض الامتدادات المسموح بها
على عكس saveFileوظيفة فئة FilePicker، pickFilesيمكن للوظيفة فرض امتدادات الملفات، بحيث يمكن للمستخدمين فقط تحديد الملفات ذات الامتدادات المحددة.
Future<void> _importFile() async =>
FilePicker.platform.pickFiles(
allowedExtensions: ['txt'],
type: FileType.custom,
).then((FilePickerResult? result) async {
if (result != null) {
final PlatformFile selectedFile = result.files.single;
if (selectedFile.path == null) {
return;
}
final File file = File(selectedFile.path!);
print(await file.readAsString());
}
});
لسوء الحظ، مع هذا النهج، لا يزال المستخدم قادرًا على تحديد الملفات ذات امتدادات الملفات المختلفة. ومع ذلك، عند الاستخدام الصحيح، لن يتعامل تطبيقك مع بيانات الملف.
إضافة رسائل Snackbar
كما فعلنا مع وظيفة التصدير، من المفيد تقديم ملاحظات للمستخدم عند فشل عملية الاستيراد أو نجاحها. لذلك، يمكننا أيضًا إضافة رسائل SnackBar إلى الوظيفة _importFile.
import 'dart:convert';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
class FilePickerPage extends StatelessWidget {
const FilePickerPage({super.key});
void _showSnackBar(BuildContext context, Color color, String text) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: color,
content: Center(child: Text(text)),
duration: const Duration(seconds: 2),
),
);
}
Future<void> _exportFile(BuildContext context) async => FilePicker.platform.saveFile(
bytes: utf8.encode('Only Flutter'),
fileName: 'only_flutter.txt',
).then((String? path) {
if (!context.mounted) return;
if (path != null) {
_showSnackBar(context, Colors.green, 'Export successful.');
} else {
_showSnackBar(context, Colors.red, 'Export failed.');
}
});
Future<void> _importFile(BuildContext context) async =>
FilePicker.platform.pickFiles(
allowedExtensions: ['txt'],
type: FileType.custom,
).then((FilePickerResult? result) async {
if (!context.mounted) return;
if (result != null) {
final PlatformFile selectedFile = result.files.single;
if (selectedFile.path == null) {
_showSnackBar(context, Colors.red, 'Import failed.');
return;
}
final File file = File(selectedFile.path!);
await file.readAsString().then((String text) {
if (!context.mounted) return;
_showSnackBar(context, Colors.green, text);
});
return;
}
_showSnackBar(context, Colors.red, 'Import failed.');
});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () async => _exportFile(context),
child: const Text('Export File'),
),
ElevatedButton(
onPressed: () async => _importFile(context),
child: const Text('Import File'),
),
],
),
),
);
}
}
في مقتطف التعليمات البرمجية أعلاه، قمنا بإعادة استخدام _showSnackBarالوظيفة داخل _importFileالوظيفة لعرض رسائل SnackBar لكل من عمليات الاستيراد الناجحة والفاشلة. نظرًا لأن الوظيفة _showSnackBarتتطلب السياق، فنحن الآن نمرر السياق إلى الوظيفة _importFileأيضًا.
في هذا المنشور، تعلمت كيفية تصدير واستيراد الملفات باستخدام حزمة File Picker في Flutter. وكما رأيت، فإن الحزمة سهلة الاستخدام وباستخدام الحد الأدنى من التعليمات البرمجية، يمكنك بالفعل تحقيق الكثير. كما ناقشنا خيارات التخصيص مثل تقييد ملحقات الملفات وتقديم الملاحظات للمستخدمين لإبقائهم على اطلاع بحالة عمليات الملفات الخاصة بهم.