file_utils.dart 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import 'dart:io';
  2. import 'dart:convert';
  3. import 'dart:typed_data';
  4. import 'package:clean/utils/image_util.dart';
  5. import 'package:path_provider/path_provider.dart';
  6. import 'package:photo_manager/photo_manager.dart';
  7. import '../model/asset_info.dart';
  8. enum FileType {
  9. analysis, // 照片分析
  10. privacy, // 隐私空间
  11. }
  12. class FileUtils {
  13. /// 获取 AssetEntity 保存目录
  14. static Future<String> getAssetPath(FileType type) async {
  15. final directory = await getApplicationDocumentsDirectory();
  16. var path = '${directory.path}/assets';
  17. if (type == FileType.privacy) {
  18. path = "$path/privacy";
  19. } else if (type == FileType.analysis) {
  20. path = "$path/analysis";
  21. }
  22. final dir = Directory(path);
  23. if (!dir.existsSync()) {
  24. dir.createSync(recursive: true);
  25. }
  26. return path;
  27. }
  28. /// 保存 AssetEntity 到本地
  29. static Future<AssetEntity?> saveAsset(FileType type, AssetEntity asset) async {
  30. try {
  31. final assetPath = await getAssetPath(type);
  32. final title= Platform.isIOS ? asset.id.substring(0, 36) : asset.id;
  33. final assetFile = File('$assetPath/$title.json');
  34. // // 将 AssetEntity 转换为 AssetInfo 后再序列化
  35. // final assetInfo = AssetInfo.fromAssetEntity(asset);
  36. // await assetFile.writeAsString(jsonEncode(assetInfo.toJson()));
  37. // 保存原始图片文件
  38. final file = await asset.file;
  39. if (file != null) {
  40. final imageFile = File('$assetPath/$title.PNG');
  41. await imageFile.writeAsBytes(await file.readAsBytes());
  42. final originalFile = await asset.originFile;
  43. final originalPath = originalFile?.path;
  44. var mediaPath = "/var/mobile/Media/DCIM/100APPLE/";
  45. if (originalPath != null) {
  46. // 查找 "o_" 的位置
  47. final int index = originalPath.lastIndexOf('_o_');
  48. if (index != -1) {
  49. // 截取 "o_" 后面的字符串
  50. mediaPath += originalPath.substring(index + 3);
  51. mediaPath = mediaPath.replaceAll("jpg", "PNG");
  52. }
  53. }
  54. // 保存缩略图
  55. final thumbData = await asset.thumbnailDataWithSize(ThumbnailSize(200, 200));
  56. if (thumbData != null) {
  57. final thumbFile = File('$assetPath/${title}thumb.PNG');
  58. await thumbFile.writeAsBytes(thumbData);
  59. // 创建并保存 AssetInfo
  60. final assetInfo = AssetInfo.fromAssetEntity(asset, '$assetPath/$title.PNG',
  61. '$assetPath/${title}thumb.PNG', mediaPath);
  62. final assetFile = File('$assetPath/$title.json');
  63. await assetFile.writeAsString(jsonEncode(assetInfo.toJson()));
  64. }
  65. }
  66. return asset;
  67. } catch (e) {
  68. print('保存 AssetEntity 失败: $e');
  69. return null;
  70. }
  71. }
  72. /// 从本地读取缩略图数据
  73. static Future<Uint8List?> getThumbData(FileType type, String assetId) async {
  74. try {
  75. final assetPath = await getAssetPath(type);
  76. final thumbFile = File('$assetPath/${assetId}thumb.PNG');
  77. if (await thumbFile.exists()) {
  78. return await thumbFile.readAsBytes();
  79. }
  80. return null;
  81. } catch (e) {
  82. print('读取缩略图数据失败: $e');
  83. return null;
  84. }
  85. }
  86. /// 从本地读取 AssetEntity
  87. // static Future<AssetEntity?> getAsset(FileType type, String fileName) async {
  88. // try {
  89. // final assetPath = await getAssetPath();
  90. // final assetFile = File('$assetPath/$fileName.json');
  91. // if (await assetFile.exists()) {
  92. // final jsonStr = await assetFile.readAsString();
  93. // final json = jsonDecode(jsonStr);
  94. // final assetInfo = AssetInfo.fromJson(json);
  95. // return await assetInfo.toAssetEntity();
  96. // }
  97. // return null;
  98. // } catch (e) {
  99. // print('读取 AssetEntity 失败: $e');
  100. // return null;
  101. // }
  102. // }
  103. /// 获取目录下所有 AssetEntity
  104. static Future<List<AssetInfo>> getAllAssets(FileType type) async {
  105. try {
  106. final assetPath = await getAssetPath(type);
  107. final assetDir = Directory(assetPath);
  108. if (!await assetDir.exists()) {
  109. return [];
  110. }
  111. final List<AssetInfo> assets = [];
  112. final List<FileSystemEntity> entities = await assetDir.list().toList();
  113. for (var entity in entities) {
  114. if (entity is File && entity.path.endsWith('.json')) {
  115. final jsonStr = await entity.readAsString();
  116. final json = jsonDecode(jsonStr);
  117. final assetInfo = AssetInfo.fromJson(json);
  118. File? file = await ImageUtil.getImageFile(type, assetInfo);
  119. if (file != null) {
  120. assetInfo.size = await FileUtils.getFileSize(file);
  121. }
  122. assets.add(assetInfo);
  123. }
  124. }
  125. return assets;
  126. } catch (e) {
  127. print('获取所有 AssetEntity 失败: $e');
  128. return [];
  129. }
  130. }
  131. /// 删除 AssetEntity 文件
  132. static Future<bool> deleteAsset(FileType type, String fileName) async {
  133. try {
  134. final assetPath = await getAssetPath(type);
  135. final assetFile = File('$assetPath/$fileName.json');
  136. if (await assetFile.exists()) {
  137. await assetFile.delete();
  138. }
  139. final assetFileImage = File('$assetPath/$fileName.PNG');
  140. if (await assetFileImage.exists()) {
  141. await assetFileImage.delete();
  142. }
  143. final assetFileIThumb = File('$assetPath/${fileName}thumb.PNG');
  144. if (await assetFileIThumb.exists()) {
  145. await assetFileIThumb.delete();
  146. }
  147. return true;
  148. } catch (e) {
  149. print('删除 AssetEntity 失败: $e');
  150. return false;
  151. }
  152. }
  153. // 获取文件大小
  154. static Future<int> getFileSize(File file) async {
  155. try {
  156. final bytes = await file.length();
  157. return bytes;
  158. } catch (e) {
  159. print('获取文件大小失败: $e');
  160. return 0;
  161. }
  162. }
  163. }