
老孟導讀:Flutter 中獲取檔案路徑,我們都知道使用 path_provider,但對其目錄對含義不是很清楚,此文介紹 Android、iOS 系統的檔案目錄,不同場景下建議使用的目錄,
不同的平臺對應的檔案系統是不同的,比如檔案路徑,因此 Flutter 中獲取檔案路徑需要原生支持,原生端通過 MethodChannel 傳遞檔案路徑到 Flutter,如果沒有特殊的需求,推薦大家使用 Google 官方維護的插件 path_provider,
pub 地址:https://pub.flutter-io.cn/packages/path_provider
Github 地址:https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider
添加依賴
在專案的 pubspec.yaml 檔案中添加依賴:
dependencies:
path_provider: ^1.6.14
執行命令:
flutter pub get
檔案路徑
path_provider(版本:1.6.14)提供了8個方法獲取不同的檔案路徑,目前 Flutter(Flutter 1.20.1 ? channel stable )只發布了正式版本的 Android 和 iOS,因此下面僅介紹 Android 和 iOS 平臺的檔案路徑,
-
getTemporaryDirectory
臨時目錄,適用于下載的快取檔案,此目錄隨時可以清除,此目錄為應用程式私有目錄,其他應用程式無法訪問此目錄,
Android 上對應
getCacheDir,iOS上對應
NSCachesDirectory, -
getApplicationSupportDirectory
應用程式可以在其中放置應用程式支持檔案的目錄的路徑,
將此檔案用于您不想向用戶公開的檔案, 您的應用不應將此目錄用于存放用戶資料檔案,
在iOS上,對應
NSApplicationSupportDirectory,如果此目錄不存在,則會自動創建,
在Android上,對應getFilesDir, -
getLibraryDirectory
應用程式可以在其中存盤持久性檔案,備份檔案以及對用戶不可見的檔案的目錄路徑,例如storage.sqlite.db,
在Android上,此函式拋出[UnsupportedError]例外,沒有等效項路徑存在,
-
getApplicationDocumentsDirectory
應用程式可能在其中放置用戶生成的資料或應用程式無法重新創建的資料的目錄路徑,
在iOS上,對應
NSDocumentDirectoryAPI, 如果資料不是用戶生成的,考慮使用[getApplicationSupportDirectory],在Android上,對應
getDataDirectoryAPI, 如果要讓用戶看到資料,請考慮改用[getExternalStorageDirectory], -
getExternalStorageDirectory
應用程式可以訪問頂級存盤的目錄的路徑,由于此功能僅在Android上可用,因此應在發出此函式呼叫之前確定當前作業系統,
在iOS上,此功能會引發[UnsupportedError]例外,因為無法在應用程式的沙箱外部訪問,
在Android上,對應
getExternalFilesDir(null), -
getExternalCacheDirectories
存盤特定于應用程式的外部快取資料的目錄的路徑, 這些路徑通常位于外部存盤(如單獨的磁區或SD卡)上, 電話可能具有多個可用的存盤目錄,
由于此功能僅在Android上可用,因此應在發出此函式呼叫之前確定當前作業系統,
在iOS上,此功能會拋出UnsupportedError,因為這是不可能的在應用程式的沙箱外部訪問,在Android上,對應
Context.getExternalCacheDirs()或API Level 低于19的Context.getExternalCacheDir(), -
getExternalStorageDirectories
可以存盤應用程式特定資料的目錄的路徑, 這些路徑通常位于外部存盤(如單獨的磁區或SD卡)上,
由于此功能僅在Android上可用,因此應在發出此函式呼叫之前確定當前作業系統,
在iOS上,此功能會拋出UnsupportedError,因為這是不可能的在應用程式的沙箱外部訪問,
在Android上,對應Context.getExternalFilesDirs(String type)或API Level 低于19的Context.getExternalFilesDir(String type), -
getDownloadsDirectory
存盤下載檔案的目錄的路徑,這通常僅與臺式機作業系統有關,
在Android和iOS上,此函式將引發[UnsupportedError]例外,
如果沒有 Android 或者 iOS開發經驗,看完上面的說明應該是一臉懵逼的,這么多路徑到呼叫哪個?有什么區別?下面從 Android 和 iOS 平臺的角度介紹其檔案路徑,最后給出路徑使用的建議以及使用程序中需要注意的事項,
Android 檔案存盤
Android 檔案存盤分為內部存盤和外部存盤,
內部存盤
用于保存應用的私有檔案,其他應用無法訪問這些資料,創建的檔案在此應用的包名目錄下,沒有 root 權限 的手機無法在手機的 檔案管理 應用中看到此目錄,不過可以通過 Android Studio 工具查看,路徑為:data/data/包名:

看下包名下具體的目錄結構:

- cache 目錄:對應 getTemporaryDirectory 方法,用于快取檔案,此目錄隨時可能被系統清除,
- files 目錄:對應 getApplicationSupportDirectory 方法,
- code_cache:此目錄存盤 Flutter 相關代碼和資源,
- flutter_engine/skia:Flutter 渲染引擎,
- flutter_guidePVWGWK/flutter_guide/build/flutter_assets:Flutter 資源檔案,
- shared_prefs: SharePreferences 的默認路徑,
- app_flutter:對應 getApplicationDocumentsDirectory方法,
- app_flutter/dbName:使用 sqlite 的默認路徑,sqlite 也可以指定位置,
SharePreferences 和 sqlite 是兩種保存資料的第三方插件,
內部存盤的特點:
- 安全性,其他應用無法訪問這些資料,
- 當應用卸載的時候,這些資料也會被洗掉,避免垃圾檔案,
- 不需要申請額外權限,
- 存盤的空間有限,此目錄資料隨時可能被系統清除,也可以通過 設定 中的 清除資料 可以清除此目錄資料,
- 國內特色,不同手機廠商對此目錄做了不同的限制,比如總體大小限制、單個應用程式所占空間大小限制、清除資料策略不同等,
外部存盤
外部存盤可以通過手機的 檔案管理 應用查看,

這里面有一個特殊的目錄:Android/data/包名:

看到這個目錄是不是覺得和內部存盤目錄非常相似,一個包名代表一個應用程式:

- cache:快取目錄,對應 getExternalCacheDirectories 方法,
- files:對應 getExternalStorageDirectories 方法,
此目錄的特點:
- 當應用卸載的時候,這些資料也會被洗掉,避免垃圾檔案,
- 不需要申請額外權限,
- 空間大且不會被系統清除,通過 設定 中的 清除資料 可以清除此目錄資料,
- 用戶可以直接對檔案進行洗掉、匯入操作,
外部存盤除了 Android/data/ 目錄,還有和此目錄同級的目錄,特點:
- 所有應用程式均可訪問,
- 用戶可以直接對檔案進行洗掉、匯入操作,
- 需要申請讀寫權限,
Android 官方對此目錄的管理越來越嚴格, Android 11 系統已經開始強制執行磁區存盤,詳情見:https://developer.android.com/preview/privacy/storage?hl=zh-cn
上面說了這么多,總結如下:
- SharePreferences 和 sqlite 資料建議存放在內部存盤,插件已經幫我們完成了,無需手動處理,
- 嚴格保密的資料,比如用戶資料,建議存放在內部存盤,對應 getApplicationSupportDirectory 方法,
- 其余所有的資料建議存放 Android/data/包名/ ,對應 getExternalCacheDirectories 和 getExternalStorageDirectories 方法,
iOS 檔案存盤
iOS 檔案存盤相比 Android 要簡單的多,因為 iOS 對用戶隱私保護非常嚴格,每個 iOS 應用程式都有一個單獨的檔案系統,而且只能在對應的檔案系統中進行操作,此區域被稱為沙盒,
每個應用沙盒含有3個檔案夾:Documents, Library 和 tmp:

- Documents:應用程式資料檔案寫入到這個目錄下,這個目錄用于存盤用戶資料,保存應用程式的重要資料檔案和用戶資料檔案等,iTunes 同步時會備份該目錄,對應 getApplicationDocumentsDirectory 方法,
- Library:對應 getLibraryDirectory 方法,
- Caches:保存應用程式使用時產生的支持檔案、快取檔案、日志檔案等,比如下載的音樂,視頻,SDWebImage快取等,對應 getTemporaryDirectory 方法,
- Preferences:包含應用程式的偏好設定檔案,iCloud會備份設定資訊,
- Application Support:對應 getApplicationSupportDirectory 方法,
- tmp:存放臨時檔案,不會被備份,而且這個檔案下的資料有可能隨時被清除的可能,按照官方說法每三天清理一次快取資料,
path_provider 使用
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
///
/// desc:
///
class PathProviderDemo extends StatefulWidget {
@override
_PathProviderDemoState createState() => _PathProviderDemoState();
}
class _PathProviderDemoState extends State<PathProviderDemo> {
Future<Directory> _tempDirectory;
Future<Directory> _appSupportDirectory;
Future<Directory> _appLibraryDirectory;
Future<Directory> _appDocumentsDirectory;
Future<Directory> _externalStorageDirectory;
Future<List<Directory>> _externalStorageDirectories;
Future<List<Directory>> _externalCacheDirectories;
Future<Directory> _downloadDirectory;
@override
void initState() {
super.initState();
setState(() {
_tempDirectory = getTemporaryDirectory();
_appSupportDirectory = getApplicationSupportDirectory();
_appLibraryDirectory = getLibraryDirectory();
_appDocumentsDirectory = getApplicationDocumentsDirectory();
_externalStorageDirectory = getExternalStorageDirectory();
_externalCacheDirectories = getExternalCacheDirectories();
_externalStorageDirectories = getExternalStorageDirectories();
_downloadDirectory = getDownloadsDirectory();
});
}
Widget _buildDirectory(
BuildContext context, AsyncSnapshot<Directory> snapshot) {
Text text = const Text('');
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
text = Text('Error: ${snapshot.error}');
} else if (snapshot.hasData) {
text = Text('path: ${snapshot.data.path}');
} else {
text = const Text('path unavailable');
}
}
return Padding(padding: EdgeInsets.symmetric(horizontal: 16), child: text);
}
Widget _buildDirectories(
BuildContext context, AsyncSnapshot<List<Directory>> snapshot) {
Text text = const Text('');
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
text = Text('Error: ${snapshot.error}');
} else if (snapshot.hasData) {
final String combined =
snapshot.data.map((Directory d) => d.path).join(', ');
text = Text('paths: $combined');
} else {
text = const Text('path unavailable');
}
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), child: text);
}
Widget _buildItem(String title, Future<Directory> future) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(title),
),
FutureBuilder<Directory>(future: future, builder: _buildDirectory),
],
);
}
Widget _buildItem1(String title, Future<List<Directory>> future) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(title),
),
FutureBuilder<List<Directory>>(
future: future,
builder: _buildDirectories),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: ListView(
itemExtent: 120,
children: <Widget>[
_buildItem('getTemporaryDirectory', _tempDirectory),
_buildItem('getApplicationSupportDirectory', _appSupportDirectory),
_buildItem('getLibraryDirectory', _appLibraryDirectory),
_buildItem(
'getApplicationDocumentsDirectory', _appDocumentsDirectory),
_buildItem(
'getExternalStorageDirectory', _externalStorageDirectory),
_buildItem('getDownloadsDirectory', _downloadDirectory),
_buildItem1('getExternalStorageDirectories',_externalStorageDirectories),
_buildItem1('getExternalCacheDirectories',_externalCacheDirectories),
],
),
),
);
}
}
Android 系統各個路徑:

iOS 系統各個路徑:

交流
交流
老孟Flutter博客(330個控制元件用法+實戰入門系列文章):http://laomengit.com
歡迎加入Flutter交流群(微信:laomengit)、關注公眾號【老孟Flutter】:
![]() |
![]() |
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/72607.html
標籤:Dart


