5

I'm trying to edit a XmlDocument file contained in a Zip file:

var zip = new ZipArchive(myZipFileInMemoryStream, ZipArchiveMode.Update);
var entry = zip.GetEntry("filenameToEdit");
using (var st = entry.Open())
{
    var xml = new XmlDocument();
    xml.Load(st);
    foreach (XmlElement el in xml.GetElementsByTagName("Relationship"))
    {
        if(el.HasAttribute("Target") && el.GetAttribute("Target").Contains(".dat")){
            el.SetAttribute("Target", path);
        }
    }
    xml.Save(st);
}

After executing this code the contained file is not changed. IF instead of xml.Save(st); I write the xml to disk, I got the edited one.

Why is the edited file not written to the zip? How do I fix it?

EDIT:

I updated the code:

var tmp = new MemoryStream();
using (var zip = new ZipArchive(template, ZipArchiveMode.Read, true))
{
    var entry = zip.GetEntry("xml");
    using (var st = entry.Open())
    {
        var xml = new XmlDocument();
        xml.Load(st);
        foreach (XmlElement el in xml.GetElementsByTagName("Relationship"))
        {
            if (el.HasAttribute("Target") && el.GetAttribute("Target").Contains(".dat"))
            {
                el.SetAttribute("Target", path);
            }
        }
        xml.Save(tmp);
    }
}
using (var zip = new ZipArchive(template, ZipArchiveMode.Update, true))
{
    var entry = zip.GetEntry("xml");
    using (var st = entry.Open())
    {
        tmp.Position = 0;
        tmp.CopyTo(st);
    }
}

In this way the zip file is edited, but it works only if the length of the streams is equal. If tmp is shorter the rest of the st is still in the file...

Hints?

Emaborsa
  • 2,360
  • 4
  • 28
  • 50
  • I don't see you saving the zip anywhere :) – Luaan Mar 31 '16 at 13:45
  • I skipped the part of saving `myZipFileInMemoryStream` to disk. Shouldn't the edited part be included in the stream? – Emaborsa Mar 31 '16 at 13:54
  • Apparently, it should - `After retrieving the stream, you can read from or write to the stream. When you write to the stream, the modifications you make to the entry will appear in the zip archive.` (MSDN). But you also have to rewind the stream - `st.Position = 0`, otherwise you're just adding the new XML to the end of the old one. Could that be the problem? :) – Luaan Mar 31 '16 at 14:00
  • Adding `st.Position = 0;` it throws an error `This operation is not supported` – Emaborsa Mar 31 '16 at 14:04
  • Hmm, yeah, so the stream doesn't support seeking, that isn't *too* surprising. Maybe you have to close the stream and open it again for the save? – Luaan Mar 31 '16 at 14:31
  • I updated the question. – Emaborsa Mar 31 '16 at 14:33
  • 1
    Well, ZIP doesn't really support full blown in-place update. The best solution might simply be to Delete the file and Create it again. – Luaan Mar 31 '16 at 14:50
  • This doesn't use ZipArchive -- or am I missing something? – Glenn Ferrie Oct 04 '17 at 14:07
  • `var zip = new ZipArchive(myZipFileInMemoryStream, ZipArchiveMode.Update);` isn't? – Emaborsa Oct 04 '17 at 14:58

1 Answers1

-1

I use this code to create a Zip InMemory (using the DotNetZip Library) :

        MemoryStream saveStream = new MemoryStream();

        ZipFile arrangeZipFile = new ZipFile();
        arrangeZipFile.AddEntry("test.xml", "content...");
        arrangeZipFile.Save(saveStream);

        saveStream.Seek(0, SeekOrigin.Begin);
        saveStream.Flush(); // might be useless, because it's in memory...

After that I have a valid Zip inside the MemoryStream. I'm not sure why I added the Flush() - I would guess this is redundant.

To edit an existing Zip you could read it in a MemoryStream and instead of creating "new ZipFile()" use "new ZipFile(byteArray...)".

Robert Muehsig
  • 5,206
  • 2
  • 29
  • 33
  • Does it work even if `test.xml` alredy exists? What if I want to put the file in a subfolder? What is the `content` for? – Emaborsa Apr 01 '16 at 07:19
  • arrangeZipFile.AddEntry("test.xml", "content..."); => Will create a new "text.xml" file inside the zip, which is stored in memory, with the given content. If you want to update an entry just use the UpdateEntry method. For subfolders: At least DotNetZip will just use the given path, e.g. if you want to create a subfolder just name it that way: AddEntry("subfolder/test.xml"..) – Robert Muehsig Apr 01 '16 at 09:37