šÆ Objective
Create a program that simulates downloading multiple files concurrently using async/await. You'll demonstrate concurrent operations, progress tracking, error handling, and performance measurement.
Requirements
Create a downloadFile() function that simulates downloading with Future.delayed()
Each download should take a random amount of time (500ms to 3 seconds)
Download multiple files concurrently using Future.wait()
Show progress as each file completes (with checkmarks)
Display total time taken using Stopwatch
Handle occasional download failures (simulate 10-20% failure rate)
Show summary statistics at the end
Expected Output
āāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā File Download Manager ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāā
Starting 5 downloads concurrently...
ā¬ļø Downloading: profile.jpg (1.2 MB)
ā¬ļø Downloading: document.pdf (3.5 MB)
ā¬ļø Downloading: music.mp3 (8.0 MB)
ā¬ļø Downloading: video.mp4 (45.0 MB)
ā¬ļø Downloading: archive.zip (12.3 MB)
ā
profile.jpg downloaded successfully (1.8s)
ā
music.mp3 downloaded successfully (2.1s)
ā video.mp4 download failed: Network timeout
ā
document.pdf downloaded successfully (2.9s)
ā
archive.zip downloaded successfully (3.2s)
āāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā SUMMARY ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāā
Total time: 3.2 seconds
Files downloaded: 4/5 (80%)
Files failed: 1/5 (20%)
Failed files:
ā video.mp4 - Network timeout
š Click to reveal complete solution
import 'dart:async';
import 'dart:math';
// Step 1: File info class
class FileInfo {
final String name;
final double sizeMB;
FileInfo(this.name, this.sizeMB);
}
// Step 2: Download result class
class DownloadResult {
final String filename;
final bool success;
final double timeSeconds;
final String? errorMessage;
DownloadResult({
required this.filename,
required this.success,
required this.timeSeconds,
this.errorMessage,
});
}
// Step 3: Simulated download function
Future downloadFile(FileInfo file) async {
final random = Random();
// Random delay based on file size (500ms to 3 seconds)
int baseDelay = 500 + (file.sizeMB * 50).toInt();
int delayMs = baseDelay + random.nextInt(1000);
// Simulate progress
print('ā¬ļø Downloading: ${file.name} (${file.sizeMB.toStringAsFixed(1)} MB)');
final stopwatch = Stopwatch()..start();
await Future.delayed(Duration(milliseconds: delayMs));
stopwatch.stop();
double timeSeconds = stopwatch.elapsedMilliseconds / 1000;
// Step 4: Simulate occasional failure (15% chance)
if (random.nextInt(100) < 15) {
final errors = [
'Network timeout',
'Server unreachable',
'Insufficient disk space',
'Connection interrupted',
];
String error = errors[random.nextInt(errors.length)];
print('ā ${file.name} download failed: $error');
return DownloadResult(
filename: file.name,
success: false,
timeSeconds: timeSeconds,
errorMessage: error,
);
}
print('ā
${file.name} downloaded successfully (${timeSeconds.toStringAsFixed(1)}s)');
return DownloadResult(
filename: file.name,
success: true,
timeSeconds: timeSeconds,
);
}
Future main() async {
print('āāāāāāāāāāāāāāāāāāāāāāāāāāāā');
print('ā File Download Manager ā');
print('āāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
// Step 5: Define files to download
final files = [
FileInfo('profile.jpg', 1.2),
FileInfo('document.pdf', 3.5),
FileInfo('music.mp3', 8.0),
FileInfo('video.mp4', 45.0),
FileInfo('archive.zip', 12.3),
];
print('Starting ${files.length} downloads concurrently...\n');
// Step 6: Start timing
final totalStopwatch = Stopwatch()..start();
// Step 7: Create futures for all downloads
final futures = files.map((file) => downloadFile(file));
// Step 8: Wait for all to complete
final results = await Future.wait(futures);
totalStopwatch.stop();
// Step 9: Calculate statistics
final successful = results.where((r) => r.success).toList();
final failed = results.where((r) => !r.success).toList();
double totalDownloadedMB = 0;
for (var i = 0; i < files.length; i++) {
if (results[i].success) {
totalDownloadedMB += files[i].sizeMB;
}
}
// Step 10: Display summary
print('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
print('ā SUMMARY ā');
print('āāāāāāāāāāāāāāāāāāāāāāāāāāāā');
print('Total time: ${(totalStopwatch.elapsedMilliseconds / 1000).toStringAsFixed(1)} seconds');
print('Files downloaded: ${successful.length}/${files.length} (${((successful.length/files.length)*100).toStringAsFixed(0)}%)');
print('Total data: ${totalDownloadedMB.toStringAsFixed(1)} MB');
if (failed.isNotEmpty) {
print('\nFailed files (${failed.length}/${files.length}):');
for (var result in failed) {
print(' ā ${result.filename} - ${result.errorMessage}');
}
}
// Step 11: Performance rating
double avgSpeed = totalDownloadedMB / (totalStopwatch.elapsedMilliseconds / 1000);
print('\nš Average download speed: ${avgSpeed.toStringAsFixed(2)} MB/s');
if (successful.length == files.length) {
print('š All files downloaded successfully!');
} else if (successful.length >= files.length * 0.7) {
print('š Most files downloaded successfully.');
} else {
print('ā ļø Many downloads failed. Check your connection.');
}
}