¿Cómo puedo sobrescribir el contenido de un ZipArchiveEntry? El siguiente código que usa StreamWriter con StringBuilder falla si los nuevos contenidos del archivo son más cortos que los originales, por ejemplo:

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"
   }
}

Produce un archivo que contiene contenido nuevo y antiguo mezclado "baz123123" en lugar del esperado "baz123". ¿Hay alguna forma de descartar los contenidos antiguos de ZipArchiveEntry antes de escribir los nuevos?
nota: no quiero extraer el archivo, me gustaría cambiar el contenido del archivo.

7
wondra 18 oct. 2017 a las 15:26

3 respuestas

La mejor respuesta

Actualizar el archivo significa que está agregando, moviendo o eliminando una entrada del archivo.

Considere hacer los siguientes pasos.

  • Obtener el contenido de la entrada

  • Elimine la entrada del archivo (tome nota del nombre / ubicación)

  • Modifique el contenido como lo desee.

  • Agregue contenido modificado nuevamente al archivo.

6
Nkosi 18 oct. 2017 a las 12:55

El siguiente código mantiene su estructura de código básica, pero elimina y vuelve a crear explícitamente el archivo para garantizar que no queden datos 'sobrantes'.

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);
    }
}
8
mjwills 18 oct. 2017 a las 22:07

Una alternativa es SetLength(document.Length) de la secuencia entry.Open().

using(var stream = entry.Open())
{
   stream.SetLength(document.Length);
   using (StreamWriter writer = new StreamWriter(stream))
   {
      writer.Write(document); //entry contents "baz123"
   }
}
14
wondra 19 oct. 2017 a las 07:06