Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overwrite contents of ZipArchiveEntry

How can I overwrite contents of a ZipArchiveEntry? Following code using StreamWriter with StringBuilder fails if the new file contents are shorter than the original ones, for example:

using System.IO.Compression;
//...
using (var archive = ZipFile.Open("Test.zip", ZipArchiveMode.Update))
{
   StringBuilder document;
   var entry = archive.GetEntry("foo.txt");//entry contents "foobar123"
   using (StreamReader reader = new StreamReader(entry.Open()))
   {
      document = new StringBuilder(reader.ReadToEnd());
   }

   document.Replace("foobar", "baz"); //builder contents "baz123"

   using (StreamWriter writer = new StreamWriter(entry.Open()))
   {
      writer.Write(document); //entry contents "baz123123", expected "baz123"
   }
}

Produces file containing new and old contents mixed up "baz123123" instead of expected "baz123". Is there perhaps a way how to discard the old contents of ZipArchiveEntry before writing the new ones?
note: I do not want to extract the file, I would like to change contents of the archive.

like image 521
wondra Avatar asked Oct 18 '17 12:10

wondra


3 Answers

An alternative is to SetLength(document.Length) of the entry.Open() stream.

using(var stream = entry.Open())
{
   stream.SetLength(document.Length);
   using (StreamWriter writer = new StreamWriter(stream))
   {
      writer.Write(document); //entry contents "baz123"
   }
}
like image 178
wondra Avatar answered Oct 22 '22 03:10

wondra


The below code maintains your basic code structure, but explicitly deletes and recreates the file to ensure that 'leftover' data does not remain.

using (var archive = ZipFile.Open("Test.zip", ZipArchiveMode.Update))
{
    StringBuilder document;
    var entry = archive.GetEntry("foo.txt");//entry contents "foobar123"
    using (StreamReader reader = new StreamReader(entry.Open()))
    {
       document = new StringBuilder(reader.ReadToEnd());
    }

    entry.Delete();
    entry = archive.CreateEntry("foo.txt");
    document.Replace("foobar", "baz"); //builder contents "baz123"

    using (StreamWriter writer = new StreamWriter(entry.Open()))
    {
       writer.Write(document);
    }
}
like image 12
mjwills Avatar answered Oct 22 '22 03:10

mjwills


Updating the archive means you are either adding, moving or removing an entry from the archive.

Consider doing the following steps.

  • Get the entry content

  • Remove the entry from the archive (take note of name/location)

  • Modify content as desired.

  • Add modified content back to the archive.

like image 7
Nkosi Avatar answered Oct 22 '22 02:10

Nkosi