You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
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
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>