locked
Wie auf Zip-Container zugreifen? RRS feed

  • Frage

  • Hallo,

    unsere Anwendungs-Projekt-Daten bestehen aus mehreren Dateien, die in mehreren Verzeichnissen liegen. 

    Schön wäre es diese Daten in einer Datei, quasi als Container, weitergeben zu können. Eine Möglichkeit wäre komprimieren in zip o.ä. - wobei es uns nicht aufs Komprimieren ankommt, darauf könnte verzichtet werden. Wichtig wäre das die Dateien zusammen bleiben.

    Aber der Zugriff auf die einzelnen Dateien des Projektes soll sich möglichst nicht groß ändern. Auch möchten wir nicht unbedingt mit temporären Dateien arbeiten (alles in ein temp-Verzeichnis packen und mit diesen Dateien arbeiten) da die Daten doch recht groß werden können.

    zur Info: Es arbeitet immer nur ein User an den Daten.

    Was gibt es hier für Möglichkeiten?

    Danke



    • Bearbeitet UMorgenw Mittwoch, 29. August 2018 08:26
    Mittwoch, 29. August 2018 07:47

Antworten

  • Hi,
    die einfachste und transparenteste Lösung ist aus meiner Sicht die Nutzung eines Zip-Archives.

    … wie macht man das?

    Erzeuge ein Zip-Archive und füge dort die Dateien / ByteStream o.ä ein.

    Brauche ich da nicht einen Filestream und irgendwie eine Index-Datei, die mir verrät wo ich die entsprechende Datei finde, wenn ich nicht die gesamte Datei scannen möchte?

    Du kannst über die Entries-Eigenschaft des Archives, die eine Liste des Inhaltes bereitstellt, das gewünschte Element (Datei / Bild o.ä.) finden.

    Früher konnte man unter Delphi mal Records in einer Datei speichern.

    Mit dem Zip-Archiv kannst Du dasselbe erreichen.

    Dein Link verweist auf die Möglichkeit, unverwaltete Objekte in Strukturen zu kopieren. Dieser Weg unterstützt nach meiner Meinung nicht das Ziel, was Du skizziert hast.

    ein schönes Beispiel wäre hilfreich

    Hier mal eine kleine Demo einer Konsolenanwendung in VB.NET:

    Imports IO = System.IO
    Imports Comp = System.IO.Compression ' Referenz auf System.IO.Compression
    Imports System.Text
    
    Module Module1
    
      Sub Main()
        Try
          Dim c As New Demo
          c.Execute()
        Catch ex As Exception
          Console.WriteLine(ex.Message)
        End Try
        Console.WriteLine("weiter mit Taste")
        Console.ReadKey()
      End Sub
    
      Friend Class Demo
        Friend Sub Execute()
          ' Stream erzeugen
          Dim zipStream As New IO.MemoryStream
          ' neues Zip-Archiv erzeugen
          Dim archive As Comp.ZipArchive = CreateZipArchive(zipStream)
          ' Dateien dem Archiv hinzufügen
          For i = 1 To 10
            Dim str As String = $"Text {i}"
            Dim bytes As Byte() = Encoding.Default.GetBytes(str)
            AddBytesToArchive(archive, str, bytes)
          Next
          ' Archiv schließen und neu zum Lesen öffnen
          archive = CloseReopenArchive(archive, zipStream)
          ' Dateien im Archiv anzeigen
          For Each name In GetItemNames(archive)
            Console.WriteLine(name)
          Next
          ' Archiv als Datei ablegen
          SaveZipStream(zipStream, "c:\temp\x.zip")
        End Sub
    
        Private Function CreateZipArchive(stream As IO.Stream) As Comp.ZipArchive
          Dim archive As New Comp.ZipArchive(stream, Comp.ZipArchiveMode.Create, True)
          Return archive
        End Function
    
        Private Sub AddBytesToArchive(archiv As Comp.ZipArchive, name As String, b As Byte())
          Dim entry As Comp.ZipArchiveEntry = archiv.CreateEntry(name)
          'entry.
          Using writer As IO.BinaryWriter = New IO.BinaryWriter(entry.Open())
            writer.Write(b, 0, b.Length)
          End Using
        End Sub
    
        Private Function CloseReopenArchive(archiv As Comp.ZipArchive, stream As IO.Stream) As Comp.ZipArchive
          archiv.Dispose()
          Return New Comp.ZipArchive(stream, Comp.ZipArchiveMode.Read, True)
        End Function
    
        Private Iterator Function GetItemNames(archive As Comp.ZipArchive) As IEnumerable(Of String)
          For Each item As Comp.ZipArchiveEntry In archive.Entries
            Yield item.Name
          Next
        End Function
    
        Private Sub SaveZipStream(zipStream As IO.Stream, path As String)
          zipStream.Position = 0
          Using writer As IO.FileStream = New IO.FileStream(path, IO.FileMode.Create)
            zipStream.CopyTo(writer)
          End Using
        End Sub
    
      End Class
    
    End Module


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks


    Dienstag, 4. September 2018 07:04

Alle Antworten

  • Hi,

    Du wirst in allen Varianten nicht drumrum kommen, die Dateien irgendwie zu kopieren. Für das Zusammenhalten (auch ohne Komprimierung) kannst Du bspw. DotNetZip nehmen.

    Ich frage mich nur, warum Du das so machen willst?

    Wenn es darum geht, dass ein User mit der Anwendung arbeitet, dann alles zusammenpackt, an einen anderen User übermittelt und der soll dann weiterarbeiten, würde ich wie oben geschrieben, DotNetZip integrieren, eine Methode zum Packen und Versenden aller relevanter Dateien und je nach gewünschter Vorgehensweise dann noch das Gegenstück dazu (also entpacken in die Zielordner) einbauen.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Mittwoch, 29. August 2018 08:27
    Moderator
  • Hi,

    macht das Word mit docx auch so das die erst in temporären Ordner entpacken und am Ende wieder zusammen packen?

    MfG

    Mittwoch, 29. August 2018 12:35
  • Hi,

    es muss kein temporärer Ordner sein, Du kannst ja bspw. auch mit MemoryStreams arbeiten und die Dateien so aus der Zip Datei lesen und wieder speichern.

    Docx, ... sind letztendlich auch nur Zip Dateien. Wie genau da aber der interne Mechanismus zum Lesen und schreiben der enthaltenen Dateien ist, weiß ich nicht.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
    https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport

    Mittwoch, 29. August 2018 12:56
    Moderator
  • Moin,

    mal angenommen, ich möchte 100.000 Bilder in einer Datei abspeichern (komprimieren erstmal nicht nötig) und später die Bilder laden und anzeigen, evtl noch nach Bildern mit bestimmter Bezeichnung suchen - wie macht man das?

    Brauche ich da nicht einen Filestream und und irgendwie eine Index-Datei, die mir verrät wo ich die entsprechende Datei finde, wenn ich nicht die gesamte Datei scannen möchte?

    Früher konnte man unter Delphi mal Records in einer Datei speichern.

    Hiermit geht das offenbar auch, mit allen Nachteilen:

    https://msdn.microsoft.com/de-de/library/4ca6d5z7%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

    ein schönes Beispiel wäre hilfreich...

    Freitag, 31. August 2018 10:44
  • Hallo,

    man möge die *.c  -Sources von Mark Adler anwenden, die Mühe diese in einer eigen Lib zu Kompilieren lohnt.

    https://www.ncbi.nlm.nih.gov/IEB/ToolBox/CPP_DOC/lxr/source/src/util/compress/zlib/

    Grüße
     Karsten Schulz



    Montag, 3. September 2018 22:56
  • Hi,
    die einfachste und transparenteste Lösung ist aus meiner Sicht die Nutzung eines Zip-Archives.

    … wie macht man das?

    Erzeuge ein Zip-Archive und füge dort die Dateien / ByteStream o.ä ein.

    Brauche ich da nicht einen Filestream und irgendwie eine Index-Datei, die mir verrät wo ich die entsprechende Datei finde, wenn ich nicht die gesamte Datei scannen möchte?

    Du kannst über die Entries-Eigenschaft des Archives, die eine Liste des Inhaltes bereitstellt, das gewünschte Element (Datei / Bild o.ä.) finden.

    Früher konnte man unter Delphi mal Records in einer Datei speichern.

    Mit dem Zip-Archiv kannst Du dasselbe erreichen.

    Dein Link verweist auf die Möglichkeit, unverwaltete Objekte in Strukturen zu kopieren. Dieser Weg unterstützt nach meiner Meinung nicht das Ziel, was Du skizziert hast.

    ein schönes Beispiel wäre hilfreich

    Hier mal eine kleine Demo einer Konsolenanwendung in VB.NET:

    Imports IO = System.IO
    Imports Comp = System.IO.Compression ' Referenz auf System.IO.Compression
    Imports System.Text
    
    Module Module1
    
      Sub Main()
        Try
          Dim c As New Demo
          c.Execute()
        Catch ex As Exception
          Console.WriteLine(ex.Message)
        End Try
        Console.WriteLine("weiter mit Taste")
        Console.ReadKey()
      End Sub
    
      Friend Class Demo
        Friend Sub Execute()
          ' Stream erzeugen
          Dim zipStream As New IO.MemoryStream
          ' neues Zip-Archiv erzeugen
          Dim archive As Comp.ZipArchive = CreateZipArchive(zipStream)
          ' Dateien dem Archiv hinzufügen
          For i = 1 To 10
            Dim str As String = $"Text {i}"
            Dim bytes As Byte() = Encoding.Default.GetBytes(str)
            AddBytesToArchive(archive, str, bytes)
          Next
          ' Archiv schließen und neu zum Lesen öffnen
          archive = CloseReopenArchive(archive, zipStream)
          ' Dateien im Archiv anzeigen
          For Each name In GetItemNames(archive)
            Console.WriteLine(name)
          Next
          ' Archiv als Datei ablegen
          SaveZipStream(zipStream, "c:\temp\x.zip")
        End Sub
    
        Private Function CreateZipArchive(stream As IO.Stream) As Comp.ZipArchive
          Dim archive As New Comp.ZipArchive(stream, Comp.ZipArchiveMode.Create, True)
          Return archive
        End Function
    
        Private Sub AddBytesToArchive(archiv As Comp.ZipArchive, name As String, b As Byte())
          Dim entry As Comp.ZipArchiveEntry = archiv.CreateEntry(name)
          'entry.
          Using writer As IO.BinaryWriter = New IO.BinaryWriter(entry.Open())
            writer.Write(b, 0, b.Length)
          End Using
        End Sub
    
        Private Function CloseReopenArchive(archiv As Comp.ZipArchive, stream As IO.Stream) As Comp.ZipArchive
          archiv.Dispose()
          Return New Comp.ZipArchive(stream, Comp.ZipArchiveMode.Read, True)
        End Function
    
        Private Iterator Function GetItemNames(archive As Comp.ZipArchive) As IEnumerable(Of String)
          For Each item As Comp.ZipArchiveEntry In archive.Entries
            Yield item.Name
          Next
        End Function
    
        Private Sub SaveZipStream(zipStream As IO.Stream, path As String)
          zipStream.Position = 0
          Using writer As IO.FileStream = New IO.FileStream(path, IO.FileMode.Create)
            zipStream.CopyTo(writer)
          End Using
        End Sub
    
      End Class
    
    End Module


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks


    Dienstag, 4. September 2018 07:04