Skip to content

fix async 7z seeking#1200

Merged
adamhathcock merged 1 commit intomasterfrom
adam/fix-async-7z-seeking
Feb 11, 2026
Merged

fix async 7z seeking#1200
adamhathcock merged 1 commit intomasterfrom
adam/fix-async-7z-seeking

Conversation

@adamhathcock
Copy link
Owner

@adamhathcock adamhathcock commented Feb 11, 2026

Async version of #1172

Reported #1199

This pull request improves the async extraction support for 7z (SevenZip) archives, particularly solid archives, and adds new tests to ensure correct stream reuse and contiguous extraction. The main focus is on ensuring that, during extraction from solid archives, the decompression stream is reused for entries in the same folder, which is critical for performance and correctness.

Key changes include:

SevenZip Archive Extraction Improvements:

  • Added an async override GetEntryStreamAsync to SevenZipArchive, enabling proper asynchronous extraction support and aligning with the sync method.

Testing and Verification:

  • Added tests to verify that solid 7z archives extract all entries as contiguous streams and that the decompression stream is reused within a folder, preventing unnecessary stream recreations.
  • Updated test imports to include necessary namespaces for new async tests.

Copilot AI review requested due to automatic review settings February 11, 2026 12:15
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes a critical performance regression in async 7z extraction (issue #1199) by implementing proper stream reuse for solid archives, similar to the sync fix in PR #1172. Additionally, it includes extensive code quality improvements across the codebase.

Changes:

  • Fixed SevenZipReader to maintain folder stream state and reuse decompression streams across entries in solid archives, preventing recreation of streams that breaks sequential reading
  • Enhanced Dispose/DisposeAsync patterns across numerous stream classes to properly call base class disposal methods
  • Improved exception types for better error semantics (Exception → InvalidDataException/InvalidOperationException)
  • Relaxed several high-volume code analyzers from error to suggestion severity to facilitate incremental improvements
  • Added culture-invariant string operations in build scripts for consistent cross-locale behavior

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/SharpCompress.Test/SevenZip/SevenZipArchiveAsyncTests.cs Added tests to verify solid archive stream reuse behavior
src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs Implemented folder stream caching in SevenZipReader; removed SyncOnlyStream wrapper; async delegates to sync
src/SharpCompress/IO/SharpCompressStream.Async.cs Added base.DisposeAsync() call
src/SharpCompress/Compressors/ZStandard/*.cs Fixed Dispose/DisposeAsync to call base class methods
src/SharpCompress/Compressors/Xz/XZStream.cs Removed unused field and simplified constructor
src/SharpCompress/Compressors/Xz/XZBlock.cs Removed unused _checkType field
src/SharpCompress/Compressors/Squeezed/SqueezedStream.cs Removed unused _compressedSize field
src/SharpCompress/Compressors/Shrink/ShrinkStream.cs Removed unused _compressionMode field
src/SharpCompress/Compressors/Shrink/BitStream.cs Simplified unnecessary type casts
src/SharpCompress/Compressors/Rar/RarBLAKE2spStream.cs Removed unused dummy field
src/SharpCompress/Compressors/RLE90/RunLength90Stream*.cs Added parameter names to ArgumentOutOfRangeException; fixed Dispose pattern
src/SharpCompress/Compressors/Lzw/LzwStream.cs Added base.Dispose() call
src/SharpCompress/Compressors/LZMA/LzmaEncoder.cs Removed unused constants and method
src/SharpCompress/Compressors/LZMA/LZipStream.cs Fixed Dispose pattern to call base
src/SharpCompress/Compressors/Filters/DeltaFilter.cs Removed unused DISTANCE_MIN constant
src/SharpCompress/Compressors/Explode/ExplodeStream*.cs Changed Exception to InvalidDataException; added System.IO.Compression using
src/SharpCompress/Compressors/BZip2/*.cs Fixed Dispose pattern
src/SharpCompress/Compressors/Arj/LhaStream*.cs Changed Exception to InvalidDataException; added parameter name to ArgumentOutOfRangeException; removed unused field
src/SharpCompress/Common/Zip/WinzipAesCryptoStream*.cs Fixed Dispose/DisposeAsync patterns
src/SharpCompress/Common/Tar/TarReadOnlySubStream.cs Removed unused field; fixed Dispose/DisposeAsync patterns
src/SharpCompress/Common/Tar/Headers/TarHeader*.cs Changed Exception types to InvalidOperationException/InvalidDataException
src/SharpCompress/Common/Rar/Headers/*.cs Changed HostOs reads to discard; removed unused properties
src/SharpCompress/Common/Arj/Headers/*.cs Removed unused constants
src/SharpCompress/Archives/Zip/ZipArchive*.cs Removed unnecessary option conversion in SaveTo
src/SharpCompress/Archives/Tar/TarArchive*.cs Removed unnecessary option conversion in SaveTo
src/SharpCompress/Archives/GZip/GZipArchive*.cs Removed unnecessary option conversion in SaveTo
build/Program.cs Added CultureInfo.InvariantCulture for ToLower/ToUpper/Contains; improved robustness with early returns
Directory.Build.props Re-enabled analyzers by removing False settings
.editorconfig Downgraded high-volume analyzers from error to suggestion

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// Extract the entry to trigger GetEntryStream
using var entryStream = await reader.OpenEntryStreamAsync();
var buffer = new byte[4096];
while (entryStream.Read(buffer, 0, buffer.Length) > 0)
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test is using synchronous Read() instead of ReadAsync(). For an async test, this should use await entryStream.ReadAsync(buffer, 0, buffer.Length) to properly exercise the async code path. The current implementation may not fully test the async behavior that the test is designed to verify.

Suggested change
while (entryStream.Read(buffer, 0, buffer.Length) > 0)
int bytesRead;
while ((bytesRead = await entryStream.ReadAsync(buffer, 0, buffer.Length)) > 0)

Copilot uses AI. Check for mistakes.
Comment on lines +277 to +281
var buffer = new byte[4096];
while (entryStream.Read(buffer, 0, buffer.Length) > 0)
{
// Read the stream to completion
}
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty block without comment.

Suggested change
var buffer = new byte[4096];
while (entryStream.Read(buffer, 0, buffer.Length) > 0)
{
// Read the stream to completion
}
// Read the stream to completion to exercise folder stream reuse behavior
await entryStream.CopyToAsync(Stream.Null);

Copilot uses AI. Check for mistakes.
entryCount++;

var folderStream = sevenZipReader.DiagnosticsCurrentFolderStream;
var folder = sevenZipReader.DiagnosticsCurrentFolder;
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment to folder is useless, since its value is never read.

Copilot uses AI. Check for mistakes.
// Read the stream to completion
}

entryCount++;
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment to entryCount is useless, since its value is never read.

Copilot uses AI. Check for mistakes.
@adamhathcock adamhathcock merged commit 8a54f25 into master Feb 11, 2026
6 checks passed
@adamhathcock adamhathcock deleted the adam/fix-async-7z-seeking branch February 11, 2026 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant