Skip to content

Commit 425d1ea

Browse files
authored
Fix cancellation of compression & extraction (#14)
1 parent 463e1d5 commit 425d1ea

File tree

5 files changed

+36
-83
lines changed

5 files changed

+36
-83
lines changed

src/Files.App/Files.App.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
8484
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
8585
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.756" />
86-
<PackageReference Include="SevenZipSharp" Version="1.0.1" />
86+
<PackageReference Include="SevenZipSharp" Version="1.0.2" />
8787
<PackageReference Include="SQLitePCLRaw.bundle_green" Version="2.1.6" />
8888
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.231008000" />
8989
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.1.0" />

src/Files.App/Utils/Archives/CompressArchiveModel.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public class CompressArchiveModel : ICompressArchiveModel
1717

1818
private FileSizeCalculator _sizeCalculator;
1919

20+
private IThreadingService _threadingService = Ioc.Default.GetRequiredService<IThreadingService>();
21+
2022
private string ArchiveExtension => FileFormat switch
2123
{
2224
ArchiveFormats.Zip => ".zip",
@@ -147,7 +149,6 @@ public async Task<bool> RunCreationAsync()
147149
IncludeEmptyDirectories = true,
148150
EncryptHeaders = true,
149151
PreserveDirectoryRoot = sources.Length > 1,
150-
EventSynchronization = EventSynchronizationStrategy.AlwaysAsynchronous,
151152
};
152153

153154
compressor.Compressing += Compressor_Compressing;
@@ -207,8 +208,11 @@ private void Compressor_FileCompressionStarted(object? sender, FileNameEventArgs
207208
e.Cancel = true;
208209
else
209210
_sizeCalculator.ForceComputeFileSize(e.FilePath);
210-
_fileSystemProgress.FileName = e.FileName;
211-
_fileSystemProgress.Report();
211+
_threadingService.ExecuteOnUiThreadAsync(() =>
212+
{
213+
_fileSystemProgress.FileName = e.FileName;
214+
_fileSystemProgress.Report();
215+
});
212216
}
213217

214218
private void Compressor_FileCompressionFinished(object? sender, EventArgs e)

src/Files.App/Utils/Archives/DecompressHelper.cs

Lines changed: 28 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public static class DecompressHelper
1616
{
1717
private readonly static StatusCenterViewModel _statusCenterViewModel = Ioc.Default.GetRequiredService<StatusCenterViewModel>();
1818

19+
private static IThreadingService _threadingService = Ioc.Default.GetRequiredService<IThreadingService>();
20+
1921
private static async Task<SevenZipExtractor?> GetZipFile(BaseStorageFile archive, string password = "")
2022
{
2123
return await FilesystemTasks.Wrap(async () =>
@@ -40,57 +42,13 @@ public static async Task ExtractArchiveAsync(BaseStorageFile archive, BaseStorag
4042
if (zipFile is null)
4143
return;
4244

43-
var directoryEntries = new List<ArchiveFileInfo>();
44-
var fileEntries = new List<ArchiveFileInfo>();
45-
foreach (ArchiveFileInfo entry in zipFile.ArchiveFileData)
46-
{
47-
if (!entry.IsDirectory)
48-
fileEntries.Add(entry);
49-
else
50-
directoryEntries.Add(entry);
51-
}
52-
53-
if (cancellationToken.IsCancellationRequested) // Check if cancelled
54-
return;
55-
56-
var directories = new List<string>();
57-
try
58-
{
59-
directories.AddRange(directoryEntries.Select((entry) => entry.FileName));
60-
directories.AddRange(fileEntries.Select((entry) => Path.GetDirectoryName(entry.FileName)));
61-
}
62-
catch (Exception ex)
63-
{
64-
App.Logger.LogWarning(ex, $"Error transforming zip names into: {destinationFolder.Path}\n" +
65-
$"Directories: {string.Join(", ", directoryEntries.Select(x => x.FileName))}\n" +
66-
$"Files: {string.Join(", ", fileEntries.Select(x => x.FileName))}");
67-
return;
68-
}
69-
70-
foreach (var dir in directories.Distinct().OrderBy(x => x.Length))
71-
{
72-
if (!NativeFileOperationsHelper.CreateDirectoryFromApp(dir, IntPtr.Zero))
73-
{
74-
var dirName = destinationFolder.Path;
75-
foreach (var component in dir.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries))
76-
{
77-
dirName = Path.Combine(dirName, component);
78-
NativeFileOperationsHelper.CreateDirectoryFromApp(dirName, IntPtr.Zero);
79-
}
80-
}
81-
82-
if (cancellationToken.IsCancellationRequested) // Check if canceled
83-
return;
84-
}
85-
8645
if (cancellationToken.IsCancellationRequested) // Check if canceled
8746
return;
8847

8948
// Fill files
9049

9150
byte[] buffer = new byte[4096];
92-
int entriesAmount = fileEntries.Count;
93-
var minimumTime = new DateTime(1);
51+
int entriesAmount = zipFile.ArchiveFileData.Where(x => !x.IsDirectory).Count();
9452

9553
StatusCenterItemProgressModel fsProgress = new(
9654
progress,
@@ -104,47 +62,38 @@ public static async Task ExtractArchiveAsync(BaseStorageFile archive, BaseStorag
10462
zipFile.Extracting += (s, e) =>
10563
{
10664
if (fsProgress.TotalSize > 0)
107-
fsProgress.Report((fsProgress.ProcessedSize + e.PercentDelta / 100.0 * e.BytesCount) / fsProgress.TotalSize * 100);
65+
fsProgress.Report(e.BytesProcessed / (double)fsProgress.TotalSize * 100);
10866
};
109-
110-
foreach (var entry in fileEntries)
67+
zipFile.FileExtractionStarted += (s, e) =>
11168
{
112-
if (cancellationToken.IsCancellationRequested) // Check if canceled
113-
return;
114-
115-
var filePath = destinationFolder.Path;
116-
foreach (var component in entry.FileName.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
117-
filePath = Path.Combine(filePath, component);
118-
119-
var hFile = NativeFileOperationsHelper.CreateFileForWrite(filePath);
120-
if (hFile.IsInvalid)
121-
return; // TODO: handle error
122-
123-
fsProgress.FileName = entry.FileName;
124-
fsProgress.Report();
125-
126-
// We don't close hFile because FileStream.Dispose() already does that
127-
using (FileStream destinationStream = new FileStream(hFile, FileAccess.Write))
69+
if (cancellationToken.IsCancellationRequested)
70+
e.Cancel = true;
71+
if (!e.FileInfo.IsDirectory)
12872
{
129-
try
73+
_threadingService.ExecuteOnUiThreadAsync(() =>
13074
{
131-
await zipFile.ExtractFileAsync(entry.Index, destinationStream);
132-
}
133-
catch (Exception ex)
134-
{
135-
App.Logger.LogWarning(ex, $"Error extracting file: {filePath}");
136-
return; // TODO: handle error
137-
}
75+
fsProgress.FileName = e.FileInfo.FileName;
76+
fsProgress.Report();
77+
});
13878
}
139-
140-
_ = new FileInfo(filePath)
79+
};
80+
zipFile.FileExtractionFinished += (s, e) =>
81+
{
82+
if (!e.FileInfo.IsDirectory)
14183
{
142-
CreationTime = entry.CreationTime > minimumTime && entry.CreationTime < entry.LastWriteTime ? entry.CreationTime : entry.LastWriteTime,
143-
LastWriteTime = entry.LastWriteTime,
144-
};
84+
fsProgress.AddProcessedItemsCount(1);
85+
fsProgress.Report();
86+
}
87+
};
14588

146-
fsProgress.AddProcessedItemsCount(1);
147-
fsProgress.Report();
89+
try
90+
{
91+
await zipFile.ExtractArchiveAsync(destinationFolder.Path);
92+
}
93+
catch (Exception ex)
94+
{
95+
App.Logger.LogWarning(ex, $"Error extracting file: {archive.Name}");
96+
return; // TODO: handle error
14897
}
14998
}
15099

-69.9 KB
Binary file not shown.
69.9 KB
Binary file not shown.

0 commit comments

Comments
 (0)