2.dart_
2.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import 'package:dio/dio.dart';
class ParallelUploader {
final Dio dio = Dio();
final int maxConcurrentUploads;
ParallelUploader({this.maxConcurrentUploads = 3});
// 并行上传多个分片
Future<List<UploadResult>> uploadChunksParallel(
File file,
List<ChunkInfo> chunks,
String uploadUrl,
) async {
final results = <UploadResult>[];
final completed = <bool>[];
// 使用队列控制并发数量
for (int i = 0; i < chunks.length; i += maxConcurrentUploads) {
final currentBatch = chunks.sublist(
i,
i + maxConcurrentUploads > chunks.length ? chunks.length : i + maxConcurrentUploads
);
// 并行上传当前批次的分片
final batchFutures = currentBatch.map((chunk) {
return compute(_uploadSingleChunk, UploadTask(
filePath: file.path,
chunk: chunk,
uploadUrl: uploadUrl,
));
}).toList();
final batchResults = await Future.wait(batchFutures);
results.addAll(batchResults);
// 更新进度
_updateProgress(results.length, chunks.length);
}
return results;
}
void _updateProgress(int completed, int total) {
final progress = (completed / total * 100).toInt();
print('上传进度: $progress%');
}
}
// 上传任务数据类(必须是可序列化的)
class UploadTask {
final String filePath;
final ChunkInfo chunk;
final String uploadUrl;
UploadTask({
required this.filePath,
required this.chunk,
required this.uploadUrl,
});
}
// 上传结果类
class UploadResult {
final int chunkIndex;
final bool success;
final String? error;
final String? chunkId;
UploadResult({
required this.chunkIndex,
required this.success,
this.error,
this.chunkId,
});
}
// 在后台线程上传单个分片
Future<UploadResult> _uploadSingleChunk(UploadTask task) async {
try {
final file = File(task.filePath);
final chunk = task.chunk;
// 读取分片数据
final raf = file.openSync();
raf.setPositionSync(chunk.start);
final chunkData = raf.readSync(chunk.end - chunk.start);
raf.closeSync();
// 上传分片
final dio = Dio();
final formData = FormData.fromMap({
'file': MultipartFile.fromBytes(
chunkData,
filename: 'chunk-${chunk.index}'
),
'chunkIndex': chunk.index,
'totalChunks': chunk.totalChunks,
'chunkSize': chunk.end - chunk.start,
});
final response = await dio.post(
task.uploadUrl,
data: formData,
options: Options(
sendTimeout: Duration(seconds: 30),
receiveTimeout: Duration(seconds: 30),
),
);
return UploadResult(
chunkIndex: chunk.index,
success: response.statusCode == 200,
chunkId: response.data['chunkId'],
);
} catch (e) {
return UploadResult(
chunkIndex: task.chunk.index,
success: false,
error: e.toString(),
);
}
}