[PR #978] Add comprehensive async/await support for Stream I/O operations #1399

Open
opened 2026-01-29 22:20:22 +00:00 by claunia · 0 comments
Owner

Original Pull Request: https://github.com/adamhathcock/sharpcompress/pull/978

State: closed
Merged: Yes


Extends PR #976 with deep async support for compression streams (EntryStream, ZlibStream, DeflateStream, GZipStream) per maintainer request to "go deeper" on async implementation.

Changes

Core Stream Infrastructure

  • EntryStream: Added ReadAsync, FlushAsync, SkipEntryAsync, DisposeAsync
  • ZlibStream, DeflateStream, GZipStream: Added ReadAsync, WriteAsync, FlushAsync, DisposeAsync
  • ZlibBaseStream: Added async methods with finishAsync for proper async teardown
  • Utility: Added SkipAsync() overload without length parameter

From PR #976 (Integrated)

  • Public APIs: IReader.WriteEntryToAsync(), IWriter.WriteAsync(), IArchiveEntry.OpenEntryStreamAsync()
  • Bulk operations: WriteAllToDirectoryAsync(), WriteAllAsync()
  • Base streams: SharpCompressStream, SourceStream async support

Implementation Notes

  • All async methods use ConfigureAwait(false)
  • IAsyncDisposable for .NET 6+ via conditional compilation
  • Memory<T>/ReadOnlyMemory<T> overloads for modern .NET
  • ZlibBaseStream.ReadAsync delegates to sync Read (full async requires zlib codec refactor)
  • Zero breaking changes - all sync methods unchanged

Usage

// Async extraction
using var reader = ReaderFactory.Open(stream);
await reader.WriteAllToDirectoryAsync(@"C:\output", options, ct);

// Async compression with proper disposal
await using var gzip = new GZipStream(fileStream, CompressionMode.Compress);
await gzip.WriteAsync(data, 0, data.Length, ct);
await gzip.FlushAsync(ct);

// Async entry stream reading
using var entryStream = reader.OpenEntryStream();
await entryStream.ReadAsync(buffer, 0, buffer.Length, ct);

Test Coverage

Added 2 async-specific tests validating EntryStream and compression stream async operations. Total: 478 tests passing.

Original prompt

Context: There is an existing PR https://github.com/adamhathcock/sharpcompress/pull/976 created by Copilot that aimed to add async/await support for Stream I/O operations but currently has build errors and incomplete async coverage. The user wants me to rerun the Copilot coding agent to regenerate the changes, fix build errors, rebase on the latest main branch, and "go deeper": make EntryStream asynchronous as well as classes like ZlibStream and other internal stream wrappers.

Goals (high priority):

  • Re-run the coding agent to produce a new PR that builds and passes CI.
  • Rebase or base the changes on the repository's current main branch (get latest) so the diff is up-to-date.
  • Fix existing compile errors from the previous PR.
  • Convert all relevant Stream I/O to proper async/await usage throughout the codebase, not only surface methods. This includes:
    • EntryStream: change to support async read/write patterns or provide async overrides so callers can use await. Ensure buffered reads/writes are async-friendly.
    • Compression-related streams: ZlibStream, DeflateStream wrappers, and any other custom stream wrappers should support async operations and proper async disposal where applicable.
    • Any places where Stream.CopyTo / Read / Write are called synchronously on streams introduced by the PR should be updated to use their async counterparts (CopyToAsync, ReadAsync, WriteAsync) and awaited.
  • Preserve public API compatibility where feasible. If unavoidable, provide new async methods (e.g., ReadAsync/WriteAsync overloads or new Async-suffixed APIs) and keep existing sync overloads delegating to the appropriate implementations.
  • Add CancellationToken support for async methods where it makes sense.
  • Ensure ConfigureAwait(false) is used in library code where appropriate.
  • Update unit tests to include async tests and ensure existing tests are fixed to compile and run.
  • Update XML docs or README if any public API changes occur.

Scope details / implementation notes for the agent:

  • Start by fetching the latest main branch (or target branch) and rebase the working branch onto it.
  • Run a repository-wide search for usages of EntryStream, ZlibStream, and other custom streams introduced in the original PR; update all call sites to use async methods.
  • Update class hierarchies where necessary to add async virtual methods and implement them across derived classes.
  • For stream wrappers that override Stream.Read/Write, ensure ReadAsync/WriteAsync and BeginRead/BeginWrite are implemented where applicable, and Stream.CanRead/CanWrite semantics preserved.
  • Ensure proper disposal patterns: IAsyncDisposable where appropriate and overriding DisposeAsync/Dispose.
  • Run build and unit tests locally in the agent environment; iterate until green or until a reasonable set of compile/test errors are resolved.
  • Keep changes focused to the goal (async stream I/O) — avoid unrelated refactors unless required to fix build/test failures.

PR requirements:

  • Create a new pull request in the repository 'adamhathcock/sharpcompress' with a clear title and description that references the original PR #976 and summarizes the fixes (rebase, build fixes, EntryStream/ZlibStream async conversion, tests updated).
  • Include a checklist in the PR description indicating: Rebased onto latest, Build compiles, Tests updated and passing (or list failing tests if any remain), Public API changes documented, and Migration notes if necessary.

If any decisions are ambiguous or require maintainers' guidance (e.g., acceptable API breaking changes), note those decisions in the PR description so maintainers can review.

User-provided directives (follow exactly): "fixes the build errors, gets the latest and goes deeper, EntryStream should be changed to be asynchronous as well as classes like ZlibStream"

Do not open additional unrelated changes. Target branch: main (use latest main as base).

This pull request was created as a result of the following prompt from Copilot chat.

Context: There is an existing PR https://github.com/adamhathcock/sharpcompress/pull/976 created by Copilot that aimed to add async/await support for Stream I/O operations but currently has build errors and incomplete async coverage. The user wants me to rerun the Copilot coding agent to regenerate the changes, fix build errors, rebase on the latest main branch, and "go deeper": make EntryStream asynchronous as well as classes like ZlibStream and other internal stream wrappers.

Goals (high priority):

  • Re-run the coding agent to produce a new PR that builds and passes CI.
  • Rebase or base the changes on the repository's current main branch (get latest) so the diff is up-to-date.
  • Fix existing compile errors from the previous PR.
  • Convert all relevant Stream I/O to proper async/await usage throughout the codebase, not only surface methods. This includes:
    • EntryStream: change to support async read/write patterns or provide async overrides so callers can use await. Ensure buffered reads/writes are async-friendly.
    • Compression-related streams: ZlibStream, DeflateStream wrappers, and any other custom stream wrappers should support async operations and proper async disposal where applicable.
    • Any places where Stream.CopyTo / Read / Write are called synchronously on streams introduced by the PR should be updated to use their async counterparts (CopyToAsync, ReadAsync, WriteAsync) and awaited.
  • Preserve public API compatibility where feasible. If unavoidable, provide new async methods (e.g., ReadAsync/WriteAsync overloads or new Async-suffixed APIs) and keep existing sync overloads delegating to the appropriate implementations.
  • Add CancellationToken support for async methods where it makes sense.
  • Ensure ConfigureAwait(false) is used in library code where appropriate.
  • Update unit tests to include async tests and ensure existing tests are fixed to compile and run.
  • Update XML docs or README if any public API changes occur.

Scope details / implementation notes for the agent:

  • Start by fetching the latest main branch (or target branch) and rebase the working branch onto it.
  • Run a repository-wide search for usages of EntryStream, ZlibStream, and other custom streams introduced in the original PR; update all call sites to use async methods.
  • Update class hierarchies where necessary to add async virtual methods and implement them across derived classes.
  • For stream wrappers that override Stream.Read/Write, ensure ReadAsync/WriteAsync and BeginRead/BeginWrite are implemented where applicable, and Stream.CanRead/CanWrite semantics preserved.
  • Ensure proper disposal patterns: IAsyncDisposable where appropriate and overriding DisposeAsync/Dispose.
  • Run build and unit tests locally in the agent environment; iterate until green or until a reasonable set of compile/test errors are resolved.
  • Keep changes focused to the goal (async stream I/O) — avoid unrelated refactors unless required to fix build/test failures.

PR requirements:

  • Create a new pull request in the repository 'adamhathcock/sharpcompress' with a clear title and description that references the original PR #976 and summarizes the fixes (rebase, build fixes, EntryStream/ZlibStream async conversion, tests updated).
  • Include a checklist in the PR description indicating: Rebased onto latest, Build compiles, Tests updated and passing (or list failing tests if any remain), Public API changes documented, and Migration notes if necessary.

If any decisions are ambiguous or require maintainers' guidance (e.g., acceptable API breaking changes), note those decisions in the PR description so maintainers can review.

User-provided directives (follow exactly): "fixes the build errors, gets the latest and goes deeper, EntryStream should be changed to be asynchronous as well as classes like ZlibStream"

Do not open additional unrelated changes. Target branch: main (use latest main as base).


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

**Original Pull Request:** https://github.com/adamhathcock/sharpcompress/pull/978 **State:** closed **Merged:** Yes --- Extends PR #976 with deep async support for compression streams (EntryStream, ZlibStream, DeflateStream, GZipStream) per maintainer request to "go deeper" on async implementation. ## Changes **Core Stream Infrastructure** - `EntryStream`: Added `ReadAsync`, `FlushAsync`, `SkipEntryAsync`, `DisposeAsync` - `ZlibStream`, `DeflateStream`, `GZipStream`: Added `ReadAsync`, `WriteAsync`, `FlushAsync`, `DisposeAsync` - `ZlibBaseStream`: Added async methods with `finishAsync` for proper async teardown - `Utility`: Added `SkipAsync()` overload without length parameter **From PR #976 (Integrated)** - Public APIs: `IReader.WriteEntryToAsync()`, `IWriter.WriteAsync()`, `IArchiveEntry.OpenEntryStreamAsync()` - Bulk operations: `WriteAllToDirectoryAsync()`, `WriteAllAsync()` - Base streams: `SharpCompressStream`, `SourceStream` async support **Implementation Notes** - All async methods use `ConfigureAwait(false)` - `IAsyncDisposable` for .NET 6+ via conditional compilation - `Memory<T>`/`ReadOnlyMemory<T>` overloads for modern .NET - ZlibBaseStream.ReadAsync delegates to sync Read (full async requires zlib codec refactor) - Zero breaking changes - all sync methods unchanged ## Usage ```csharp // Async extraction using var reader = ReaderFactory.Open(stream); await reader.WriteAllToDirectoryAsync(@"C:\output", options, ct); // Async compression with proper disposal await using var gzip = new GZipStream(fileStream, CompressionMode.Compress); await gzip.WriteAsync(data, 0, data.Length, ct); await gzip.FlushAsync(ct); // Async entry stream reading using var entryStream = reader.OpenEntryStream(); await entryStream.ReadAsync(buffer, 0, buffer.Length, ct); ``` ## Test Coverage Added 2 async-specific tests validating EntryStream and compression stream async operations. Total: 478 tests passing. <!-- START COPILOT CODING AGENT SUFFIX --> <details> <summary>Original prompt</summary> > Context: There is an existing PR https://github.com/adamhathcock/sharpcompress/pull/976 created by Copilot that aimed to add async/await support for Stream I/O operations but currently has build errors and incomplete async coverage. The user wants me to rerun the Copilot coding agent to regenerate the changes, fix build errors, rebase on the latest main branch, and "go deeper": make EntryStream asynchronous as well as classes like ZlibStream and other internal stream wrappers. > > Goals (high priority): > - Re-run the coding agent to produce a new PR that builds and passes CI. > - Rebase or base the changes on the repository's current main branch (get latest) so the diff is up-to-date. > - Fix existing compile errors from the previous PR. > - Convert all relevant Stream I/O to proper async/await usage throughout the codebase, not only surface methods. This includes: > - EntryStream: change to support async read/write patterns or provide async overrides so callers can use await. Ensure buffered reads/writes are async-friendly. > - Compression-related streams: ZlibStream, DeflateStream wrappers, and any other custom stream wrappers should support async operations and proper async disposal where applicable. > - Any places where Stream.CopyTo / Read / Write are called synchronously on streams introduced by the PR should be updated to use their async counterparts (CopyToAsync, ReadAsync, WriteAsync) and awaited. > - Preserve public API compatibility where feasible. If unavoidable, provide new async methods (e.g., ReadAsync/WriteAsync overloads or new Async-suffixed APIs) and keep existing sync overloads delegating to the appropriate implementations. > - Add CancellationToken support for async methods where it makes sense. > - Ensure ConfigureAwait(false) is used in library code where appropriate. > - Update unit tests to include async tests and ensure existing tests are fixed to compile and run. > - Update XML docs or README if any public API changes occur. > > Scope details / implementation notes for the agent: > - Start by fetching the latest main branch (or target branch) and rebase the working branch onto it. > - Run a repository-wide search for usages of EntryStream, ZlibStream, and other custom streams introduced in the original PR; update all call sites to use async methods. > - Update class hierarchies where necessary to add async virtual methods and implement them across derived classes. > - For stream wrappers that override Stream.Read/Write, ensure ReadAsync/WriteAsync and BeginRead/BeginWrite are implemented where applicable, and Stream.CanRead/CanWrite semantics preserved. > - Ensure proper disposal patterns: IAsyncDisposable where appropriate and overriding DisposeAsync/Dispose. > - Run build and unit tests locally in the agent environment; iterate until green or until a reasonable set of compile/test errors are resolved. > - Keep changes focused to the goal (async stream I/O) — avoid unrelated refactors unless required to fix build/test failures. > > PR requirements: > - Create a new pull request in the repository 'adamhathcock/sharpcompress' with a clear title and description that references the original PR #976 and summarizes the fixes (rebase, build fixes, EntryStream/ZlibStream async conversion, tests updated). > - Include a checklist in the PR description indicating: Rebased onto latest, Build compiles, Tests updated and passing (or list failing tests if any remain), Public API changes documented, and Migration notes if necessary. > > If any decisions are ambiguous or require maintainers' guidance (e.g., acceptable API breaking changes), note those decisions in the PR description so maintainers can review. > > User-provided directives (follow exactly): "fixes the build errors, gets the latest and goes deeper, EntryStream should be changed to be asynchronous as well as classes like ZlibStream" > > Do not open additional unrelated changes. Target branch: main (use latest main as base). </details> *This pull request was created as a result of the following prompt from Copilot chat.* > Context: There is an existing PR https://github.com/adamhathcock/sharpcompress/pull/976 created by Copilot that aimed to add async/await support for Stream I/O operations but currently has build errors and incomplete async coverage. The user wants me to rerun the Copilot coding agent to regenerate the changes, fix build errors, rebase on the latest main branch, and "go deeper": make EntryStream asynchronous as well as classes like ZlibStream and other internal stream wrappers. > > Goals (high priority): > - Re-run the coding agent to produce a new PR that builds and passes CI. > - Rebase or base the changes on the repository's current main branch (get latest) so the diff is up-to-date. > - Fix existing compile errors from the previous PR. > - Convert all relevant Stream I/O to proper async/await usage throughout the codebase, not only surface methods. This includes: > - EntryStream: change to support async read/write patterns or provide async overrides so callers can use await. Ensure buffered reads/writes are async-friendly. > - Compression-related streams: ZlibStream, DeflateStream wrappers, and any other custom stream wrappers should support async operations and proper async disposal where applicable. > - Any places where Stream.CopyTo / Read / Write are called synchronously on streams introduced by the PR should be updated to use their async counterparts (CopyToAsync, ReadAsync, WriteAsync) and awaited. > - Preserve public API compatibility where feasible. If unavoidable, provide new async methods (e.g., ReadAsync/WriteAsync overloads or new Async-suffixed APIs) and keep existing sync overloads delegating to the appropriate implementations. > - Add CancellationToken support for async methods where it makes sense. > - Ensure ConfigureAwait(false) is used in library code where appropriate. > - Update unit tests to include async tests and ensure existing tests are fixed to compile and run. > - Update XML docs or README if any public API changes occur. > > Scope details / implementation notes for the agent: > - Start by fetching the latest main branch (or target branch) and rebase the working branch onto it. > - Run a repository-wide search for usages of EntryStream, ZlibStream, and other custom streams introduced in the original PR; update all call sites to use async methods. > - Update class hierarchies where necessary to add async virtual methods and implement them across derived classes. > - For stream wrappers that override Stream.Read/Write, ensure ReadAsync/WriteAsync and BeginRead/BeginWrite are implemented where applicable, and Stream.CanRead/CanWrite semantics preserved. > - Ensure proper disposal patterns: IAsyncDisposable where appropriate and overriding DisposeAsync/Dispose. > - Run build and unit tests locally in the agent environment; iterate until green or until a reasonable set of compile/test errors are resolved. > - Keep changes focused to the goal (async stream I/O) — avoid unrelated refactors unless required to fix build/test failures. > > PR requirements: > - Create a new pull request in the repository 'adamhathcock/sharpcompress' with a clear title and description that references the original PR #976 and summarizes the fixes (rebase, build fixes, EntryStream/ZlibStream async conversion, tests updated). > - Include a checklist in the PR description indicating: Rebased onto latest, Build compiles, Tests updated and passing (or list failing tests if any remain), Public API changes documented, and Migration notes if necessary. > > If any decisions are ambiguous or require maintainers' guidance (e.g., acceptable API breaking changes), note those decisions in the PR description so maintainers can review. > > User-provided directives (follow exactly): "fixes the build errors, gets the latest and goes deeper, EntryStream should be changed to be asynchronous as well as classes like ZlibStream" > > Do not open additional unrelated changes. Target branch: main (use latest main as base). <!-- START COPILOT CODING AGENT TIPS --> --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.
claunia added the pull-request label 2026-01-29 22:20:22 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/sharpcompress#1399