Flutter因为只是一个UI系统,不具备操作原生系统的能力,所以不能直接操作文件系统,因此只能借助插件来实现该功能。provider_path 是pub上使用比较多的一个插件,下面我们开始接入插件来完成相应的文件读写功能。
一、依赖
添加依赖
dependencies:
path_provider: ^2.0.1
二、使用
1. getApplicationSupportDirectory()
在 Android 获取的是 /data/data/packagename/files 目录,等同于调用getFilesDir() 方法,而在iOS中相当于调用 NSApplicationSupportDirectory。这些目录都是程序私有的,其他程序不会访问到,适合存放一些用户信息等隐私内容。
//创建App私有文件 /data/data/pkgname/
//严格保密的数据,比如用户数据,建议存放在内部存储,对应 getApplicationSupportDirectory 方法。
void createAppSupportDir() async {
Directory dir = await getApplicationSupportDirectory();
log("createApplicationSupportDir ${dir.path}");
//createApplicationSupportDir /data/user/0/com.example.flutter_widgets/files
String filePath = "${dir.path}/hello.txt";
File file = File(filePath);
if (!file.existsSync()){
file.createSync();
}
//向文件写入内容
file.writeAsStringSync("Happy New Year");
//读取文件的内容
String data = file.readAsStringSync();
log("readData from files $data");
}
2. getTemporyDirectory()
在Android中是 /data/data/packagename/cache/目录,相当于调用getCacheDir()方法,在iOS中调用 NSCachesDirectory,这个目录会随机被清除,只适合存储下载文件的缓存。
// On Android, this uses the `getCacheDir` API on the context.
void createAppTempDir() async {
Directory tempDir = await getTemporaryDirectory();
log("createAppTempDir ${tempDir.path}");
//[log] createAppTempDir /data/user/0/com.example.flutter_widgets/cache
String filePath = "${tempDir.path}/temp.txt";
File file = File(filePath);
if (!file.existsSync()){
file.createSync();
}
//向文件写入内容
file.writeAsStringSync("Happy Chinese New Year");
//读取文件的内容
String data = file.readAsStringSync();
log("readData from temp files: $data");
}
3. getExternalCacheDirectories()
在Android中,获取的是 /emulated/0/Android/Data/packagname/cache目录,相当于调用 Context.getExternalCacheDirs() 或者在API 19以下调用Context.getExternalCacheDir(),在iOS中调用会抛出异常。该目录是用指定外部缓存数据,因为手机可能存在多个外部存储卡,所以可能会有多个存储路径。
//其余所有的数据建议存放 Android/data/包名/ ,
//对应 getExternalCacheDirectories 和 getExternalStorageDirectories 方法。
void createAppExternalCacheDir() async {
List<Directory>? dirs = await getExternalCacheDirectories();
dirs!.forEach((subDir) {
print("subDir $subDir");
});
//I/flutter (22031): subDir Directory: '/storage/emulated/0/Android/data/com.example.flutter_widgets/cache'
//I/flutter (22031): subDir Directory: '/storage/0DEB-3D0A/Android/data/com.example.flutter_widgets/cache'
}
4. getExternalStorageDirectory()
在Android 中,获取的是/mnt/sdcard/Android/data/packagename/files/目录,该应用程序能够访问到的最高层级的存储路径,相当于调用 getExternalFilesDir(),该方法只能在Android中使用,iOS 不能使用,会抛出异常。
void createExternalStorageDir() async{
Directory? dir = await getExternalStorageDirectory();
log("createExternalStorageDir ${dir!.path}");
// createExternalStorageDir /storage/emulated/0/Android/data/com.example.flutter_widgets/files
String filePath = "${dir.path}/external_store.txt";
File file = File(filePath);
if (!file.existsSync()){
file.createSync();
}
//向文件写入内容
file.writeAsStringSync("Happy Tiger Year");
//读取文件的内容
String data = file.readAsStringSync();
///mnt/sdcard/Android/data/com.example.flutter_widgets/files/external_store.txt
log("readData from files $data");
}
5. getExternalStorageDirectories()
在Android中,获取的是/mnt/sdcard/Android/data/packagename/files/目录,该函数的实现如下:
Future<List<Directory>?> getExternalStorageDirectories({
/// Optional parameter. See [StorageDirectory] for more informations on
/// how this type translates to Android storage directories.
StorageDirectory? type,
}) async {
final List<String>? paths =
await _platform.getExternalStoragePaths(type: type);
if (paths == null) {
return null;
}
return paths.map((String path) => Directory(path)).toList();
}
enum StorageDirectory {
/// Contains audio files that should be treated as music.
music,
/// Contains audio files that should be treated as podcasts.
podcasts,
/// Contains audio files that should be treated as ringtones.
ringtones,
/// Contains audio files that should be treated as alarm sounds.
alarms,
/// Contains audio files that should be treated as notification sounds.
notifications,
/// Contains images.
pictures,
movies,
/// Contains files of any type that have been downloaded by the user.
downloads,
/// Used to hold both pictures and videos when the device filesystem is
/// treated like a camera's.
dcim,
/// Holds user-created documents.
documents,
}
如上可以知道,该函数有可选参数能够获取存取不同内容的目录。该函数只能在Android上使用,不能在iOS平台上使用,会抛出异常。
//存储在 /mnt/sdcard/Android/data/packagenmae/files/目录下的
void createExternalStorageDirs() async{
List<Directory>? dirs = await getExternalStorageDirectories();
dirs!.forEach((element) {
log("createExternalStorageDirs ${element.path}");
});
//[log] createExternalStorageDirs /storage/emulated/0/Android/data/com.example.flutter_widgets/files
//[log] createExternalStorageDirs /storage/0DEB-3D0A/Android/data/com.example.flutter_widgets/files
}
6. getApplicationDocumentsDirectory()
在Android中,获取的是 /data/data/packagename/app_flutter/ 目录,该目录是用存储一些用户产生的,或者一些不能被应用程序重新创建的数据,相当于调用 getDataDirectory(),如果数据是对用户可见的,那么就考虑使用 getExternalStorageDirectory() 方法,而不是该方法。在iOS中,该方法相当于调用 NSDocumentDirectory() 方法,如果数据不是用户自产生的,考虑使用 getApplicagtionSupportDirectory() 。
//getApplicationDocumentsDirectory 是存储在 /data/data/packagename/app_flutter/ 目录下的
void createDocumentDir() async {
Directory dir = await getApplicationDocumentsDirectory();
log("createDocumentDir ${dir.path}");// createDocumentDir /data/user/0/com.example.flutter_widgets/app_flutter
String filePath = "${dir.path}/document.txt";
File file = File(filePath);
if (!file.existsSync()){
file.createSync();
}
//向文件写入内容
file.writeAsStringSync("Happy Chinese New Year From Document");
//读取文件的内容
String data = file.readAsStringSync();
log("readData from document files: $data path ${file.absolute.path}");
// /data/data/com.example.flutter_widgets/app_flutter/document.txt
}
总结:
从上面的API来看,使用最多的就是 getApplicationSupport() 目录,因为该目录兼容性比较好,可以存入用户的隐私数据,也可以存储一些其他内容数据。现在 Android 的权限管理越来越严格,基本上程序只能访问自己所能管理的目录,对于其他的目录其实没有必要去获取,比如图片和视频相册,可以依靠第三方的插件来完成即可。
参考: