开发者

Is it possible to use System.IO.Packaging.Package to zip a folder and add files/folders later to it?

I wonder if we can use the .net class ZipPackage to zip a folder to a file.zip file. And then开发者_运维问答, I want open file.zip and add more files/folders into it. Is it possible?

[Edit]

I'm trying to use native .net library if possible


Native library is not a pure zipper, though it can be used to archive files. It adds extra file in your zip's root. If you don't mind this extra file then use it. There are other libraries, that do archiving the proper way, and are faster, easier to use, and with ore features: DotNetZip and SharpZipLib.


The Package class is used to handle packages, which uses the zip format for storage, but has special meta files included in the zip. A package is a zip, but all zip files aren't packages. You can only open a package using the Package class, not any zip file.

A third party library would probably be better, as you are not restricted to the form of a package.


You can use the native Zip classes provided by the J# library still supported in .NET - you do have to add a reference to vjslib to your project to enable these.

Sample code:

using java.io;
using java.util.zip;

...
private void ZipFile(string sourceFile, string targetName, ref ZipOutputStream zipout)
{
    // read the temporary file to a file source
    java.io.FileInputStream fileSourceInputStream = new java.io.FileInputStream(sourceFile);

    // create a zip entry
    ZipEntry ze = new ZipEntry(targetName);
    ze.setMethod(ZipEntry.DEFLATED);
    zipout.putNextEntry(ze);

    // stream the file to the zip
    CopyStream(fileSourceInputStream, zipout);
    zipout.closeEntry();

    // flush all data to the zip
    fileSourceInputStream.close();
    zipout.flush();
}

private static void CopyStream(java.io.InputStream from, java.io.OutputStream to)
{
    BufferedInputStream input = new BufferedInputStream(from);
    BufferedOutputStream output = new BufferedOutputStream(to);
    sbyte[] buffer = new sbyte[16384];
    int got;
    while ((got = input.read(buffer, 0, buffer.Length)) > 0)
    {
        output.write(buffer, 0, got);
    }
    output.flush();
}


Based on http://weblogs.asp.net/albertpascual/archive/2009/05/18/creating-a-folder-inside-the-zip-file-with-system-io-packaging.aspx

Here's what I developped, 2 signatures, so you can create directories in your zip file :

Imports System.IO
Imports System.IO.Packaging

Public Class clsCompression

    Const BUFFER_SIZE As Long = 4096

    Sub New()
    End Sub


    Public Function AddFileToZip(ByVal zipFilename As String, _
                                 ByVal fileToAdd As String, _
                                 ByVal directoryFile As String) As Boolean
        Dim trace As String = ""

        Try
            trace = String.Format("{0} AddFileToZip zipFilename: '{1}' fileToAdd: '{2}'{3}", _
                                  Now, zipFilename, fileToAdd, vbNewLine)
            Using zip As Package = System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate)
                Dim destFilename As String = ".\" & directoryFile & "\" & Path.GetFileName(fileToAdd)
                Dim uri As Uri = PackUriHelper.CreatePartUri(New Uri(destFilename, UriKind.Relative))
                If zip.PartExists(uri) Then
                    zip.DeletePart(uri)
                End If
                Dim part As PackagePart = zip.CreatePart(uri, "", CompressionOption.Normal)
                Using fileStream As New FileStream(fileToAdd, FileMode.Open, FileAccess.Read)
                    Using dest As Stream = part.GetStream()
                        CopyStream(fileStream, dest)
                    End Using
                End Using
            End Using
            Return True

        Catch ex As Exception
            Return False
        End Try

    End Function

    Public Function AddFileToZip(ByVal zipFilename As String, ByVal fileToAdd As String) As Boolean
        Dim trace As String = ""

        Try
            trace = String.Format("{0} AddFileToZip zipFilename: '{1}' fileToAdd: '{2}'{3}", _
                                  Now, zipFilename, fileToAdd, vbNewLine)
            Using zip As Package = System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate)
                Dim destFilename As String = ".\" & Path.GetFileName(fileToAdd)
                Dim uri As Uri = PackUriHelper.CreatePartUri(New Uri(destFilename, UriKind.Relative))
                If zip.PartExists(uri) Then
                    zip.DeletePart(uri)
                End If
                Dim part As PackagePart = zip.CreatePart(uri, "", CompressionOption.Normal)
                Using fileStream As New FileStream(fileToAdd, FileMode.Open, FileAccess.Read)
                    Using dest As Stream = part.GetStream()
                        CopyStream(fileStream, dest)
                    End Using
                End Using
            End Using
            Return True

        Catch ex As Exception
            Return False
        End Try

    End Function

    Private Sub CopyStream(ByVal inputStream As System.IO.FileStream, ByVal outputStream As System.IO.Stream)
        Dim bufferSize As Long = If(inputStream.Length < BUFFER_SIZE, inputStream.Length, BUFFER_SIZE)
        Dim buffer As Byte() = New Byte(CInt(bufferSize) - 1) {}
        Dim bytesRead As Integer = 0
        Dim bytesWritten As Long = 0
        While (InlineAssignHelper(bytesRead, inputStream.Read(buffer, 0, buffer.Length))) <> 0
            outputStream.Write(buffer, 0, bytesRead)
            bytesWritten += bufferSize
        End While
    End Sub

    Private Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
        target = value
        Return value
    End Function

End Class


It can be done with pure .NET 3.0. Using SharpZipLib may not be desirable due to the modified GPL license.

First, you will need a reference to WindowsBase.dll.

This code will open or create a zip file, create a directory inside, and place the file in that directory. If you want to zip a folder, possibly containing sub-directories, you could loop through the files in the directory and call this method for each file. Then, you could depth-first search the sub-directories for files, call the method for each of those and pass in the path to create that hierarchy within the zip file.

public void AddFileToZip(string zipFilename, string fileToAdd, string destDir)
{
    using (Package zip = System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate))
    {
        string destFilename = "." + destDir + "\\" + Path.GetFileName(fileToAdd);
        Uri uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));
        if (zip.PartExists(uri))
        {
            zip.DeletePart(uri);
        }
        PackagePart part = zip.CreatePart(uri, "", CompressionOption.Normal);

        using (FileStream fileStream = new FileStream(fileToAdd, FileMode.Open, FileAccess.Read))
        {
            using (Stream dest = part.GetStream())
            {
                CopyStream(fileStream, dest);
            }
        }
    }
}

destDir could be an empty string, which would place the file directly in the zip.

Sources: https://weblogs.asp.net/jongalloway/creating-zip-archives-in-net-without-an-external-library-like-sharpziplib

https://weblogs.asp.net/albertpascual/creating-a-folder-inside-the-zip-file-with-system-io-packaging

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜