Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

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

Closed
adschmu opened this issue May 5, 2023 · 3 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.IO.Compression

Comments

@adschmu
Copy link

adschmu commented May 5, 2023

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))

with

            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.

@adschmu adschmu added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label May 5, 2023
@ghost ghost added the untriaged New issue has not been triaged by the area owner label May 5, 2023
@ghost
Copy link

ghost commented May 5, 2023

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))

with

            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>
  <tr>
    <th align="left">Author:</th>
    <td>adschmu</td>
  </tr>
  <tr>
    <th align="left">Assignees:</th>
    <td>-</td>
  </tr>
  <tr>
    <th align="left">Labels:</th>
    <td>

`api-suggestion`, `area-System.IO.Compression`

</td>
  </tr>
  <tr>
    <th align="left">Milestone:</th>
    <td>-</td>
  </tr>
</table>
</details>

@halgab
Copy link
Contributor

halgab commented May 6, 2023

Duplicate of #1555?

@adschmu
Copy link
Author

adschmu commented May 8, 2023

Duplicate of #1555?

Looks like it. #1555 goes further by also adding new API for extraction, but otherwise seems similar. It also suggests the overload with "encoding" which IMO we probably do not need, but since the other one is accepted, the people implementing it will take care I suspect.

@adschmu adschmu closed this as completed May 8, 2023
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label May 8, 2023
@adschmu adschmu closed this as not planned Won't fix, can't repro, duplicate, stale May 8, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Jun 7, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.IO.Compression
Projects
None yet
Development

No branches or pull requests

2 participants