添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account [API Proposal]: System.IO.Compression: ZipFile.CreateFromDirectory: Provide overload for writing to stream #85822 [API Proposal]: System.IO.Compression: ZipFile.CreateFromDirectory: Provide overload for writing to stream #85822 adschmu opened this issue May 5, 2023 · 3 comments

Background and motivation

When providing a zipped file of a directory for download, there are cases where I prefer to compile the zip archive in memory, without having to write it to disk.

This essentially requires the functionality in ZipFile.CreateFromDirectory, but with a stream for the second argument instead of a file path. From a functional perspective, everything needed is already there, only the construction of the ZipArchive class inside DoCreateFromDirectory needs to be changed from calling Open() to constructing a new ZipArchive with a stream.

A locally modified version of the official code (as of .NET 6) already has been working fine for us for a year now; the downside of keeping this locally is that the implementation of DoCreateFromDirectory plus two private utility methods (EntryFromPath and EnsureCapacity) have to be copied from the official sources and thus are not receiving updates anymore.

Precisely, my local version replaces

https://github.com/dotnet/runtime/blob/v6.0.15/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Create.cs#L366

            using (ZipArchive archive = Open(destinationArchiveFileName, ZipArchiveMode.Create, entryNameEncoding))
            using (ZipArchive archive = new ZipArchive(destinationStream, ZipArchiveMode.Create))

and obviously removes the GetFullPath statement before that. The new API would require the private method to switch between these two construction mechanisms for the ZipArchive only.

API Proposal

namespace System.IO.Compression;
public static partial class ZipFile
    public static void CreateFromDirectory(
        string sourceDirectoryName,
        Stream destinationStream
    public static void CreateFromDirectory(
        string sourceDirectoryName,
        Stream destinationStream,
        CompressionLevel compressionLevel,
        bool includeBaseDirectory
    // An equivalent to the third original overload with entryNameEncoding
    // may not be necessary when a Stream is provided

API Usage

// Source directory
string sourceDirPath = "some path on disk";
// Compress and write to stream
MemoryStream zipStream;
using (zipStream = new MemoryStream())
    ZipFile.CreateFromDirectory(sourceDirPath, zipStream, CompressionLevel.Fastest, false);
// Do something with the file
byte[] file = zipStream.ToArray()
// Pseudo code: Return from ASP.NET Core MVC action
string filename = "filename for web download.zip";
return File(file, System.Net.Mime.MediaTypeNames.Application.Zip, filename);

Alternative Designs

Since DoCreateFromDirectory() is private and ZipFileUtils/ArchivingUtils class is internal, there is not much else one can do instead of just copying the stuff. Making the latter public would reduce the amount of copied code by about 50 %, but since only one line is different it still seems not desirable having to keep the other 50 % copied either.

Tagging subscribers to this area: @dotnet/area-system-io-compression
See info in area-owners.md if you want to be subscribed.

Issue Details

Background and motivation

When providing a zipped file of a directory for download, there are cases where I prefer to compile the zip archive in memory, without having to write it to disk (into a temporary file).

This essentially requires the functionality in ZipFile.CreateFromDirectory, but with a stream for the second argument instead of a file path. From a functional perspective, everything needed is already there, only the construction of the ZipArchive class inside DoCreateFromDirectory needs to be changed from calling Open() to constructing a new ZipArchive with a stream.

A locally modified version of the official code (as of .NET 6) already has been working fine for us for a year now; the downside of keeping this locally is that a few private utility methods have to be copied from the official sources as well and thus are not receiving updates anymore (in particular EntryFromPath and EnsureCapacity).

Precisely, my local version replaces

https://github.com/dotnet/runtime/blob/v6.0.15/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Create.cs#L366

            using (ZipArchive archive = Open(destinationArchiveFileName, ZipArchiveMode.Create, entryNameEncoding))
            using (ZipArchive archive = new ZipArchive(destinationStream, ZipArchiveMode.Create))

and obviously removes the GetFullPath statement before that. The new API would require the private method to switch between these two construction mechanisms for the ZipArchive only.

API Proposal

namespace System.IO.Compression;
public static partial class ZipFile
    public static void CreateFromDirectory(
        string sourceDirectoryName,
        Stream destinationStream
    public static void CreateFromDirectory(
        string sourceDirectoryName,
        Stream destinationStream,
        CompressionLevel compressionLevel,
        bool includeBaseDirectory
    // An equivalent to the third original overload with entryNameEncoding
    // may not be necessary when a Stream is provided

API Usage

// Source directory
string path = "some path on disk";
// Compress and write to stream
MemoryStream zipStream;
using (zipStream = new MemoryStream())
    ZipFile.CreateFromDirectory(tempDir, zipStream, CompressionLevel.Fastest, false);
// Do something with the file
byte[] file = zipStream.ToArray()
// Pseudo code: Return from ASP.NET Core MVC action
string filename = "filename for web download.zip";
return File(file, System.Net.Mime.MediaTypeNames.Application.Zip, filename);
### Alternative Designs
Since DoCreateFromDirectory() is private and ZipFileUtils/ArchivingUtils class is internal, there is not much else one can do instead of just copying the stuff. Making the latter public would reduce the amount of copied code by about 50 %, but only one line is different it still seems not desirable having to keep the other 50 % copied either.
### Risks
_No response_
<table>
    <th align="left">Author:</th>
    <td>adschmu</td>
    <th align="left">Assignees:</th>
    <td>-</td>
    <th align="left">Labels:</th>
`api-suggestion`, `area-System.IO.Compression`
    <th align="left">Milestone:</th>
    <td>-</td>
</table>
</details>