file_size_calculator_util.dart 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import 'dart:ffi';
  2. import 'dart:io';
  3. import 'package:classify_photo/classify_photo.dart';
  4. import 'package:flutter/cupertino.dart';
  5. import 'package:wechat_assets_picker/wechat_assets_picker.dart';
  6. import 'package:photo_manager/photo_manager.dart';
  7. class FileSizeCalculatorUtil {
  8. static final Map<String, double> fileSizeCache = {};
  9. static Future<void> calculateTotalSizeByIOS({
  10. required Set<String> assetIds,
  11. required Function(double) updateValue,
  12. }) async {
  13. if (assetIds.isEmpty) {
  14. updateValue(0);
  15. return;
  16. }
  17. double totalSize = 0;
  18. const batchSize = 20;
  19. final idList = assetIds.toList();
  20. for (int i = 0; i < idList.length; i += batchSize) {
  21. if (assetIds.isEmpty) {
  22. updateValue(0);
  23. return;
  24. }
  25. final batch = idList.skip(i).take(batchSize);
  26. final sizes = await Future.wait(
  27. batch.map((id) async {
  28. try {
  29. final size = await ClassifyPhoto().calculatePhotosSize([id]);
  30. return size / 1024; // 转 KB
  31. } catch (e) {
  32. return 0.0;
  33. }
  34. }),
  35. );
  36. totalSize += sizes.fold(0.0, (sum, size) => sum + size);
  37. if (assetIds.isEmpty) {
  38. updateValue(0);
  39. return;
  40. }
  41. await Future.delayed(Duration.zero); // 避免卡 UI
  42. updateValue(totalSize);
  43. }
  44. updateValue(totalSize);
  45. }
  46. static Future<void> calculateTotalSizeByAndroid({
  47. required Set<String> assetIds,
  48. required Function(double) updateValue,
  49. }) async {
  50. if (assetIds.isEmpty) {
  51. updateValue(0);
  52. return;
  53. }
  54. double totalSize = 0;
  55. final uncasedIds =
  56. assetIds.where((id) => !fileSizeCache.containsKey(id)).toSet();
  57. // **1️⃣ 先处理缓存中的文件**
  58. totalSize = assetIds.fold(0, (prev, id) => prev + (fileSizeCache[id] ?? 0));
  59. updateValue(totalSize);
  60. // **2️⃣ 分批处理未缓存的文件**
  61. const batchSize = 20;
  62. for (int i = 0; i < uncasedIds.length; i += batchSize) {
  63. if (assetIds.isEmpty) {
  64. updateValue(0);
  65. return;
  66. }
  67. final batch = uncasedIds.skip(i).take(batchSize);
  68. final sizes =
  69. await Future.wait(batch.map(FileSizeCalculatorUtil.getFileSize));
  70. totalSize += sizes.fold(0, (sum, size) => sum + size);
  71. // **再检查一次是否被清空,避免无意义计算**
  72. if (assetIds.isEmpty) {
  73. updateValue(0);
  74. return;
  75. }
  76. await Future.delayed(Duration.zero);
  77. updateValue(totalSize);
  78. }
  79. updateValue(totalSize);
  80. }
  81. static Future<void> calculateTotalSize({
  82. required Set<String> assetIds,
  83. required Function(double) updateValue,
  84. }) async {
  85. if (Platform.isIOS) {
  86. await calculateTotalSizeByIOS(
  87. assetIds: assetIds, updateValue: updateValue);
  88. } else {
  89. await calculateTotalSizeByAndroid(
  90. assetIds: assetIds, updateValue: updateValue);
  91. }
  92. }
  93. /// 获取文件大小
  94. static Future<double> getFileSize(String assetId) async {
  95. if (fileSizeCache.containsKey(assetId)) {
  96. return fileSizeCache[assetId]!;
  97. }
  98. final entity = await AssetEntity.fromId(assetId);
  99. if (entity == null) return 0;
  100. if (Platform.isAndroid) {
  101. final String? path = entity.relativePath;
  102. if (path == null) return 0;
  103. final file = File("/storage/emulated/0/$path${entity.title}");
  104. // print("file path: ${await file.path}");
  105. if (!await file.exists()) {
  106. return 0;
  107. }
  108. // print("file size: ${await file.length()}");
  109. final double size = (await file.length()) / 1024;
  110. fileSizeCache[assetId] = size;
  111. return size;
  112. } else {
  113. final file = await entity.file;
  114. if (file == null) return 0;
  115. if (!await file.exists()) {
  116. return 0;
  117. }
  118. try {
  119. final double size = (await file.length()) / 1024;
  120. fileSizeCache[assetId] = size;
  121. try {
  122. await file.delete();
  123. } catch (e) {
  124. debugPrint("Delete file error: $e");
  125. }
  126. if (size <= 0) {
  127. return 0;
  128. }
  129. return size;
  130. } catch (e) {
  131. return 0;
  132. }
  133. }
  134. }
  135. }