file_size_calculator_util.dart 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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. totalSize =
  19. await ClassifyPhoto().calculatePhotosSize(assetIds.toList()) / 1024;
  20. updateValue(totalSize);
  21. }
  22. static Future<void> calculateTotalSizeByAndroid({
  23. required Set<String> assetIds,
  24. required Function(double) updateValue,
  25. }) async {
  26. if (assetIds.isEmpty) {
  27. updateValue(0);
  28. return;
  29. }
  30. double totalSize = 0;
  31. final uncasedIds =
  32. assetIds.where((id) => !fileSizeCache.containsKey(id)).toSet();
  33. // **1️⃣ 先处理缓存中的文件**
  34. totalSize = assetIds.fold(0, (prev, id) => prev + (fileSizeCache[id] ?? 0));
  35. updateValue(totalSize);
  36. // **2️⃣ 分批处理未缓存的文件**
  37. const batchSize = 20;
  38. for (int i = 0; i < uncasedIds.length; i += batchSize) {
  39. if (assetIds.isEmpty) {
  40. updateValue(0);
  41. return;
  42. }
  43. final batch = uncasedIds.skip(i).take(batchSize);
  44. final sizes =
  45. await Future.wait(batch.map(FileSizeCalculatorUtil.getFileSize));
  46. totalSize += sizes.fold(0, (sum, size) => sum + size);
  47. // **再检查一次是否被清空,避免无意义计算**
  48. if (assetIds.isEmpty) {
  49. updateValue(0);
  50. return;
  51. }
  52. await Future.delayed(Duration.zero);
  53. updateValue(totalSize);
  54. }
  55. updateValue(totalSize);
  56. }
  57. static Future<void> calculateTotalSize({
  58. required Set<String> assetIds,
  59. required Function(double) updateValue,
  60. }) async {
  61. if (Platform.isIOS) {
  62. await calculateTotalSizeByIOS(
  63. assetIds: assetIds, updateValue: updateValue);
  64. } else {
  65. await calculateTotalSizeByAndroid(
  66. assetIds: assetIds, updateValue: updateValue);
  67. }
  68. }
  69. /// 获取文件大小
  70. static Future<double> getFileSize(String assetId) async {
  71. if (fileSizeCache.containsKey(assetId)) {
  72. return fileSizeCache[assetId]!;
  73. }
  74. final entity = await AssetEntity.fromId(assetId);
  75. if (entity == null) return 0;
  76. if (Platform.isAndroid) {
  77. final String? path = entity.relativePath;
  78. if (path == null) return 0;
  79. final file = File("/storage/emulated/0/$path${entity.title}");
  80. print("file path: ${await file.path}");
  81. if (!await file.exists()) {
  82. return 0;
  83. }
  84. print("file size: ${await file.length()}");
  85. final double size = (await file.length()) / 1024;
  86. fileSizeCache[assetId] = size;
  87. return size;
  88. } else {
  89. final file = await entity.file;
  90. if (file == null) return 0;
  91. if (!await file.exists()) {
  92. return 0;
  93. }
  94. try {
  95. final double size = (await file.length()) / 1024;
  96. fileSizeCache[assetId] = size;
  97. try {
  98. await file.delete();
  99. } catch (e) {
  100. debugPrint("Delete file error: $e");
  101. }
  102. if (size <= 0) {
  103. return 0;
  104. }
  105. return size;
  106. } catch (e) {
  107. return 0;
  108. }
  109. }
  110. }
  111. }