Laden...

Fehler bei kopieren eines Streams zum Erstellen von tar.bz2-Archiv mit SharpZipLib

Erstellt von roYaL-TS vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.256 Views
R
roYaL-TS Themenstarter:in
53 Beiträge seit 2012
vor 4 Jahren
Fehler bei kopieren eines Streams zum Erstellen von tar.bz2-Archiv mit SharpZipLib

Hallo zusammen,

ich versuche aktuell ein tar.bz2 Archiv zu erstellen, doch bereits auf dem Weg dort hin werden die Dateien zerschnitten. Ich habe hier PDF-Dateien und JPGs, die mir im Byte-Array zur Verfügung stehen. Ich möchte diese der Reihe nach einem TAR-File hinzufügen und ab einer Größe von 2GB ein weiteres Erstellen.

Das Problem: Wenn das jeweils letzte Dokument in den tarStream kopiert wird, fehlen hier einige Bytes, wodurch das PDF nicht mehr zu öffnen ist. Im jeweiligen inputMemoryStream ist dies noch vollständig vorhanden. Auch wenn ich es via CopyTo in einen anderen MemoryStream schiebe bleibt dies ganz. Hat jemand hier bereits Erfahrungen mit der Lib gesammelt bzw. könnte mir eine andere empfehlen, mit der ich das entsprechend erreichen kann?

Folgenden Quellcode habe ich:


Archive archive = new Archive { Items = 0 };
TarOutputStream tarStream = new TarOutputStream(new MemoryStream());

for (int i = 0; i < Fileitems.Count; i++)
{
     Fileitems item = Fileitems[i];
     MemoryStream inputMemoryStream = new MemoryStream(ByteDocument);
     long nextSize = i != Fileitems.Count - 1 ? Fileitems[i].FileSize : 0;

     TarHeader header = new TarHeader
     {
          Name = item.Filename
     };
     TarEntry newZipEntry = new TarEntry(header)
     {
          Name = item.Filename,
          Size = inputMemoryStream.Length
     };

      if (tarStream.Length + nextSize > zipMaxSize)
      {
            archive.ZipStream = tarStream;
            archives.Add(archive);
            archive = new Archive { Items = 0 };
            tarStream = new TarOutputStream(new MemoryStream());
      }
                        
      tarStream.PutNextEntry(newZipEntry);
      inputMemoryStream.Position = 0;                        
      inputMemoryStream.CopyTo(tarStream);      <<< Hier schlägt es fehl
      tarStream.CloseEntry();
      inputMemoryStream.Dispose();
      archive.Items++;
}
archive.ZipStream = tarStream;
archives.Add(archive);

Das komprimieren der Archive folgt in einem anderen Arbeitsschritt.

“Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live”
 John Woods

16.827 Beiträge seit 2008
vor 4 Jahren

Für mich sieht das gesamte Stream-Handling insgesamt sehr fischig aus; Du orientierst Dich auch quasi Null an den Code Samples.
Was genau ist "Archive" für eine Klasse? Die gibts in SharpZipLib nicht.

Wenn man die Doku befolgen würde, sollte in etwa sowas raus kommen (ungetestet):

        public class FileItem
        {
            public long FileSize { get; set; }
            public string FileName { get; set; }
            public Byte[] Contents { get; set; }
        }

        static List<TarArchive> Pack(List<FileItem> fileItems, int maxArchiveSize, string outputFileName)
        {
            List<TarArchive> archives = new List<TarArchive>();

            using (Stream outStream = File.Create(outputFileName))
            {
                Stream archiveStream = new GZipOutputStream(outStream);
                TarArchive tarArchive = TarArchive.CreateOutputTarArchive(archiveStream);
                archives.Add(tarArchive);

                foreach (FileItem file in fileItems)
                {
                    if (tarArchive.RecordSize + file.FileSize > maxArchiveSize)
                    {
                        // create new archive
                        archiveStream = new GZipOutputStream(outStream);
                        tarArchive = TarArchive.CreateOutputTarArchive(archiveStream);
                        archives.Add(tarArchive);
                    }

                    TarEntry tarEntry = TarEntry.CreateTarEntry(file.FileName);
                    tarArchive.WriteEntry(tarEntry, true);

                    StreamUtils.Copy(archiveStream, new MemoryStream(file.Contents), new byte[4096]);

                }
            }

            return archives;
        }
R
roYaL-TS Themenstarter:in
53 Beiträge seit 2012
vor 4 Jahren

Hi,

danke für deine Antwort. Archive ist eine von mir generierte Klasse, in der ich die jeweiligen Archiv-Bytes und Infos gebündelt habe. Ich hätte dazu sagen sollen, dass ich im Nachgang bzw. bevor das tatsächliche tar.bz2-Archiv geschrieben wird, ein zusätzliches File mit Meta-Informationen hinzufüge.

Das Problem an TarArchive ist, dass dies tatsächliche Files benötigt und nicht mit Streams arbeitet. Die Dateien stehen mir aber nicht nur als Base64-String zur Verfügung (aus einer DB gelesen). Das Zwischenspeichern auf der Platte ist hier leider keine Option.

Mich wundert dennoch, dass das jeweils erste TarEntry beim kopieren des Streams (ob über die Util der Lib oder über Stream.CopyTo) nicht vollständig übertragen wird.

“Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live”
 John Woods

16.827 Beiträge seit 2008
vor 4 Jahren

Also mich wundert das nicht, so wie Du mit den Streams umgehst.