From ca84e7ed29d67ee753b333fa9201f4a3e79b0e15 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 17 Feb 2026 13:01:23 +0000 Subject: [PATCH] change docs --- docs/API.md | 13 ++++++++ docs/FORMATS.md | 19 +++++------ docs/INTERFACES.md | 81 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 100 insertions(+), 13 deletions(-) diff --git a/docs/API.md b/docs/API.md index 5ee6c0c3..6a201038 100644 --- a/docs/API.md +++ b/docs/API.md @@ -67,6 +67,19 @@ var options2 = new WriterOptions(CompressionType.Deflate) }; ``` +### Format-specific Openables (.NET 8+) + +```csharp +// Reader static openables return format-specific interfaces +using var zipReader = ZipReader.OpenReader(stream); // IZipReader +using var sevenZipReader = SevenZipReader.OpenReader(stream); // ISevenZipReader + +// Writer static openables return format-specific interfaces +using var zipWriter = ZipWriter.OpenWriter(output, new ZipWriterOptions(CompressionType.Deflate)); // IZipWriter +using var tarWriter = TarWriter.OpenWriter(output, new TarWriterOptions(CompressionType.None)); // ITarWriter +using var gzipWriter = GZipWriter.OpenWriter(output, new GZipWriterOptions()); // IGZipWriter +``` + --- ## Archive API Methods diff --git a/docs/FORMATS.md b/docs/FORMATS.md index 31b74732..7e971cc5 100644 --- a/docs/FORMATS.md +++ b/docs/FORMATS.md @@ -22,12 +22,12 @@ | Tar.LZip | LZMA | Both | TarArchive | TarReader | TarWriter (3) | | Tar.XZ | LZMA2 | Decompress | TarArchive | TarReader | TarWriter (3) | | GZip (single file) | DEFLATE | Both | GZipArchive | GZipReader | GZipWriter | -| 7Zip (4) | LZMA, LZMA2, BZip2, PPMd, BCJ, BCJ2, Deflate | Decompress | SevenZipArchive | N/A | N/A | +| 7Zip (4) | LZMA, LZMA2, BZip2, PPMd, BCJ, BCJ2, Deflate | Decompress | SevenZipArchive | SevenZipReader | N/A | 1. SOLID Rars are only supported in the RarReader API. 2. Zip format supports pkware and WinzipAES encryption. However, encrypted LZMA is not supported. Zip64 reading/writing is supported but only with seekable streams as the Zip spec doesn't support Zip64 data in post data descriptors. Deflate64 is only supported for reading. See [Zip Format Notes](#zip-format-notes) for details on multi-volume archives and streaming behavior. 3. The Tar format requires a file size in the header. If no size is specified to the TarWriter and the stream is not seekable, then an exception will be thrown. -4. The 7Zip format doesn't allow for reading as a forward-only stream so 7Zip is only supported through the Archive API. See [7Zip Format Notes](#7zip-format-notes) for details on async extraction behavior. +4. 7Zip supports sequential reader extraction through `SevenZipReader`/`ReaderFactory`, but does not support random per-entry extraction via `IExtractableArchive` (entries must be processed sequentially). See [7Zip Format Notes](#7zip-format-notes). 5. LZip has no support for extra data like the file name or timestamp. There is a default filename used when looking at the entry Key on the archive. ### Zip Format Notes @@ -37,15 +37,12 @@ ### 7Zip Format Notes -- **Async Extraction Performance**: When using async extraction methods (e.g., `ExtractAllEntries()` with `MoveToNextEntryAsync()`), each file creates its own decompression stream to avoid state corruption in the LZMA decoder. This is less efficient than synchronous extraction, which can reuse a single decompression stream for multiple files in the same folder. - - **Performance Impact**: For archives with many small files in the same compression folder, async extraction will be slower than synchronous extraction because it must: - 1. Create a new LZMA decoder for each file - 2. Skip through the decompressed data to reach each file's starting position - - **Recommendation**: For best performance with 7Zip archives, use synchronous extraction methods (`MoveToNextEntry()` and `WriteEntryToDirectory()`) when possible. Use async methods only when you need to avoid blocking the thread (e.g., in UI applications or async-only contexts). - - **Technical Details**: 7Zip archives group files into "folders" (compression units), where all files in a folder share one continuous LZMA-compressed stream. The LZMA decoder maintains internal state (dictionary window, decoder positions) that assumes sequential, non-interruptible processing. Async operations can yield control during awaits, which would corrupt this shared state. To avoid this, async extraction creates a fresh decoder stream for each file. +- 7Zip supports sequential extraction through: + - `SevenZipArchive.ExtractAllEntries()` / `ExtractAllEntriesAsync()` + - `SevenZipReader.OpenReader(...)` / `OpenAsyncReader(...)` + - `ReaderFactory.OpenReader(...)` / `OpenAsyncReader(...)` (auto-detect) +- 7Zip entries are organized into compression folders and should be processed in archive order for best performance. +- 7Zip still does **not** implement `IExtractableArchive`; individual random-access `OpenEntryStream` extraction from archive entries is not supported. ## Compression Streams diff --git a/docs/INTERFACES.md b/docs/INTERFACES.md index 3cbcf8c2..68446606 100644 --- a/docs/INTERFACES.md +++ b/docs/INTERFACES.md @@ -288,6 +288,33 @@ classDiagram IFactory <|-- IWriterFactory ``` +### Static Openable Interfaces (.NET 8+) + +```mermaid +classDiagram + direction TB + + class IReaderOpenable~TReader,TAsyncReader~ { + <> + +OpenReader(filePath, options) TReader + +OpenReader(fileInfo, options) TReader + +OpenReader(stream, options) TReader + +OpenAsyncReader(path, options, ct) ValueTask~TAsyncReader~ + +OpenAsyncReader(fileInfo, options, ct) ValueTask~TAsyncReader~ + +OpenAsyncReader(stream, options, ct) ValueTask~TAsyncReader~ + } + + class IWriterOpenable~TWriter,TAsyncWriter,TOptions~ { + <> + +OpenWriter(filePath, options) TWriter + +OpenWriter(fileInfo, options) TWriter + +OpenWriter(stream, options) TWriter + +OpenAsyncWriter(filePath, options) TAsyncWriter + +OpenAsyncWriter(fileInfo, options) TAsyncWriter + +OpenAsyncWriter(stream, options) TAsyncWriter + } +``` + --- ## Format-Specific Interfaces @@ -396,6 +423,12 @@ classDiagram class ILzwReader { <> } + class ISevenZipReader { + <> + } + class ISevenZipAsyncReader { + <> + } IReader <|-- IZipReader IAsyncReader <|-- IZipAsyncReader @@ -407,6 +440,48 @@ classDiagram IReader <|-- IArcReader IReader <|-- IArjReader IReader <|-- ILzwReader + IReader <|-- ISevenZipReader + IAsyncReader <|-- ISevenZipAsyncReader +``` + +### Writer Formats + +```mermaid +classDiagram + direction LR + + class IWriter { + <> + } + class IAsyncWriter { + <> + } + + class IZipWriter { + <> + } + class IZipAsyncWriter { + <> + } + class ITarWriter { + <> + } + class ITarAsyncWriter { + <> + } + class IGZipWriter { + <> + } + class IGZipAsyncWriter { + <> + } + + IWriter <|-- IZipWriter + IAsyncWriter <|-- IZipAsyncWriter + IWriter <|-- ITarWriter + IAsyncWriter <|-- ITarAsyncWriter + IWriter <|-- IGZipWriter + IAsyncWriter <|-- IGZipAsyncWriter ``` --- @@ -552,8 +627,10 @@ await writer.WriteAsync("file.txt", contentStream, DateTime.Now); 2. **IExtractableArchive**: Separates archives that support random entry extraction from those that don't (7Zip requires sequential processing). -3. **Marker Interfaces**: Format-specific interfaces (`IZipArchive`, `ITarReader`) are markers that allow type-safe casting when format-specific features are needed. +3. **Marker Interfaces**: Format-specific interfaces (`IZipArchive`, `ITarReader`, `IZipWriter`) are markers that allow type-safe casting when format-specific features are needed. 4. **Factory Pattern**: All instances are created through factories (`ArchiveFactory`, `ReaderFactory`, `WriterFactory`) which handle format detection and instantiation. -5. **Entry Hierarchy**: `IEntry` → `IArchiveEntry` → `IExtractableArchiveEntry` provides progressive capabilities. +5. **Static Openable Pattern (.NET 8+)**: Reader/Writer implementations can implement `IReaderOpenable<...>` and `IWriterOpenable<...>` to expose strongly-typed static `Open*` APIs. + +6. **Entry Hierarchy**: `IEntry` → `IArchiveEntry` → `IExtractableArchiveEntry` provides progressive capabilities.