path_provider各种目录的区别与文件读写与单元测试

639 阅读4分钟

各目录在各个平台的支持情况

image.png

Temporary: getTemporaryDirectory()

临时目录。临时目录是系统可以随时清空的缓存文件夹

Application Support: getApplicationSupportDirectory()

应用程序支持目录。应用程序支持目录用于不想向用户公开的文件,也就是你不想给用户看到的文件可放置在该目录中,系统不会清除该目录,只有在删除应用时才会消失。您的应用不应将此目录用于存放用户数据文件。

Application Library: getLibraryDirectory()

应用程序持久文件目录。该目录主要存储持久文件的目录,并且不会对用户公开,常用于存储数据库文件,比如sqlite.db等。

应用程序可以在其中存储持久性文件,备份文件以及对用户不可见的文件的目录路径

在Android上,此函数抛出[UnsupportedError]异常,没有等效项路径存在。

Application Documents: getApplicationDocumentsDirectory()

文档目录。文档目录用于存储只能由该应用访问的文件,系统不会清除该目录,只有在删除应用时才会消失。

应用程序可能在其中放置用户生成的数据或应用程序无法重新创建的数据的目录路径。

在iOS上,对应NSDocumentDirectory API。 如果数据不是用户生成的,考虑使用getApplicationSupportDirectory

在Android上,对应getDataDirectory API。 如果要让用户看到数据,请考虑改用getExternalStorageDirectory

Application Cache:getApplicationCacheDirectory()

放置应用程序缓存的目录。如果目录不存在会自动创建。如果系统无法提供目录,则抛出MissingPlatformDirectoryException

External Storage: getExternalStorageDirectories()

外部存储目录(单独分区)。可根据类型获取外部存储目录,如SD卡、单独分区等,和外部存储目录不同在于他是获取一个目录数组。但iOS不支持外部存储目录,目前只有Android才支持。

External Cache Directories: getExternalCacheDirectories()

外部存储缓存目录。主要用户获取应用程序特定外部缓存数据的目录,比如从SD卡或者手机上有多个存储目录的,但iOS不支持外部存储目录,目前只有Android才支持。

External Storage Directories: getExternalStorageDirectory()

外部存储目录。主要用于获取外部存储目录,如SD卡等,但iOS不支持外部存储目录,目前只有Android才支持。

Downloads: getDownloadsDirectory()

桌面程序下载目录。主要用于存储下载文件的目录,只适用于LinuxMacOSWindowsAndroidiOS平台无法使用。

Android 文件存储目录如何选择

  • SharePreferences 和 sqlite 数据建议存放在内部存储,插件已经帮我们完成了,无需手动处理。
  • 严格保密的数据,比如用户数据,建议存放在内部存储,对应 getApplicationSupportDirectory 方法。
  • 其余所有的数据建议存放 Android/data/包名/  ,对应 getExternalCacheDirectories 和 getExternalStorageDirectories 方法。

iOS 文件存储目录如何选择

  • Documents:应用程序数据文件写入到这个目录下。这个目录用于存储用户数据。保存应用程序的重要数据文件和用户数据文件等。iTunes 同步时会备份该目录,对应 getApplicationDocumentsDirectory 方法。

  • Library:对应 getLibraryDirectory 方法。

    • Caches:保存应用程序使用时产生的支持文件、缓存文件、日志文件等,比如下载的音乐,视频,SDWebImage缓存等。对应 getTemporaryDirectory 方法。
    • Preferences:包含应用程序的偏好设置文件,iCloud会备份设置信息。
    • Application Support:对应 getApplicationSupportDirectory 方法。
  • tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能,按照官方说法每三天清理一次缓存数据。

实操

/// 获取文档目录文件
Future<File> _getLocalDocumentFile() async {
  final dir = await getApplicationDocumentsDirectory();
  return File('${dir.path}/str.txt');
}

/// 获取临时目录文件
Future<File> _getLocalTemporaryFile() async {
  final dir = await getTemporaryDirectory();
  return File('${dir.path}/str.txt');
}

/// 获取应用程序目录文件
Future<File> _getLocalSupportFile() async {
  final dir = await getApplicationSupportDirectory();
  return File('${dir.path}/str.txt');
}

写入数据到文件中

String name = "Jimi";

/// 写入数据
Future<void> writeString(String str) async {
  final file = await _getLocalDocumentFile();
  await file.writeAsString(name);

  final file1 = await _getLocalTemporaryFile();
  await file1.writeAsString(name);

  final file2 = await _getLocalSupportFile();
  await file2.writeAsString(name);
  print("写入成功");
}

读取文件数据

/// 读取值
Future<void> readString() async {
  try {

    final file = await _getLocalDocumentFile();
    final result  = await file.readAsString();
    print("result-----$result");

    final file1 = await _getLocalTemporaryFile();
    final result1  = await file1.readAsString();
    print("result1-----$result1");

    final file2 = await _getLocalSupportFile();
    final result2  = await file2.readAsString();
    print("result2-----$result2");

  } catch (e) {
  }
}

单元测试

添加依赖

flutter pub add path_provider

flutter pub add dev:path_provider_platform_interface dev:plugin_platform_interface dev:flutter_test

import 'package:demo_03/src/utils/logger_util.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';

void main() async {
  TestWidgetsFlutterBinding.ensureInitialized();
  setUp(() async {
    PathProviderPlatform.instance = FakePathProviderPlatform();
  });
  test('测试getApplicationDocumentsDirectory方法', () async {
    final dbFolder = await getApplicationDocumentsDirectory();
    // 会打印mock的applicationDocumentsPath
    logger.d(dbFolder);
  });
}

const String kTemporaryPath = 'temporaryPath';
const String kApplicationSupportPath = 'applicationSupportPath';
const String kDownloadsPath = 'downloadsPath';
const String kLibraryPath = 'libraryPath';
const String kApplicationDocumentsPath = 'applicationDocumentsPath';
const String kExternalCachePath = 'externalCachePath';
const String kExternalStoragePath = 'externalStoragePath';

class FakePathProviderPlatform extends Fake
    with MockPlatformInterfaceMixin
    implements PathProviderPlatform {
  @override
  Future<String?> getTemporaryPath() async {
    return kTemporaryPath;
  }

  @override
  Future<String?> getApplicationSupportPath() async {
    return kApplicationSupportPath;
  }

  @override
  Future<String?> getLibraryPath() async {
    return kLibraryPath;
  }

  @override
  Future<String?> getApplicationDocumentsPath() async {
    return kApplicationDocumentsPath;
  }

  @override
  Future<String?> getExternalStoragePath() async {
    return kExternalStoragePath;
  }

  @override
  Future<List<String>?> getExternalCachePaths() async {
    return <String>[kExternalCachePath];
  }

  @override
  Future<List<String>?> getExternalStoragePaths({
    StorageDirectory? type,
  }) async {
    return <String>[kExternalStoragePath];
  }

  @override
  Future<String?> getDownloadsPath() async {
    return kDownloadsPath;
  }
}

class AllNullFakePathProviderPlatform extends Fake
    with MockPlatformInterfaceMixin
    implements PathProviderPlatform {
  @override
  Future<String?> getTemporaryPath() async {
    return null;
  }

  @override
  Future<String?> getApplicationSupportPath() async {
    return null;
  }

  @override
  Future<String?> getLibraryPath() async {
    return null;
  }

  @override
  Future<String?> getApplicationDocumentsPath() async {
    return null;
  }

  @override
  Future<String?> getExternalStoragePath() async {
    return null;
  }

  @override
  Future<List<String>?> getExternalCachePaths() async {
    return null;
  }

  @override
  Future<List<String>?> getExternalStoragePaths({
    StorageDirectory? type,
  }) async {
    return null;
  }

  @override
  Future<String?> getDownloadsPath() async {
    return null;
  }
}

扩展:通过dart:ioDirectory获取当前目录和系统临时目录

import 'dart:io';

import 'package:demo_03/src/utils/logger_util.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  test('获取当前目录', () {
    Directory current = Directory.current;
    logger.d(current.path);
  });

  test('获取系统临时目录', () {
    logger.d(Directory.systemTemp.path);
  });
}

参考资料

Flutter 文件读写---path_provider详解 - 掘金 (juejin.cn)

Flutter 文件读写---path_provider详解 - 个人文章 - SegmentFault 思否

【Flutter 实战】文件系统目录 - 知乎 (zhihu.com)

Flutter中目录(Directory)和文件(File)常用操作_flutter file-CSDN博客