Currently only the zip classes are included. There are the following classes:
wx.ArchiveOutput out = new wx.ArchiveOutput("test.zip"); StreamWriter txt=new StreamWriter(out.Out); out.PutNextEntry("entry1.txt"); txt.WriteLine("Some text for entry1"); out.PutNextEntry(new Uri("subdir/entry2.txt").LocalPath); txt.WriteLine("Some text for subdir/entry2.txt");
The name of each entry can be a full path, which makes it possible to store entries in subdirectories.
wx.ArchiveInput.GetNextEntry()
returns a pointer to entry object containing the meta-data for the next entry in the archive (and gives away ownership). Reading from the input stream wx.ArchiveInput
. In then returns the entry's data.
When there are no more entries, wx.ArchiveInput.GetNextEntry()
returns null
wx.ArchiveInput.In
also gets null
.
wx.ArchiveEntry entry; wx.ArchiveInput in=new wx.ArchiveInput("test.zip"); for(entry = in.GetNextEntry(); entry != null; entry = in.GetNextEntry()) { Console.Out.WriteLine(string.format("{0}\t{1}", entry.Name, entry.DateTime); }
wx.ArchiveOutput.CopyEntry()
. For archive types which compress entry data, CopyEntry() is likely to be much more efficient than transferring the data using Stream.Read() and Stream.Write() since it will copy them without decompressing and recompressing them.In general modifications are not possible without rewriting the archive, though it may be possible in some limited cases. Even then, rewriting the archive is usually a better choice since a failure can be handled without losing the whole archive.
For example to delete all entries matching the pattern "*.txt":
wx.ArchiveInput in=new wx.ArchiveInput("test.zip"); wx.ArchiveOutput out=new wx.ArchiveOutput("test-txt.zip"); out.CopyArchiveMetaData(in); for(wx.ArchiveEntry entry=in.GetNextEntry(); entry != null; entry=in.GetNextEntry) { if (!entry.Name.EndsWith("*.txt")) if (!out.CopyEntry(entry, in)) break; } // close the input stream by releasing the pointer to it, do this // before closing the output stream so that the file can be replaced in.Close(); // you can check for success as follows bool success = out.Close();
wx.ArchiveInput.GetNextEntry()
until the required entry is found. This works both for archives on seekable and non-seekable streams.
The format of filenames in the archive is likely to be different from the local filename format. For example zips and tars use unix style names, with forward slashes as the path separator, and absolute paths are not allowed. So if on Windows the file "C:\MYDIR\MYFILE.TXT" is stored, then when reading the entry back wx.ArchiveEntry.Name
will return "MYDIR\MYFILE.TXT". The conversion into the internal format and back has lost some information.
So to avoid ambiguity when searching for an entry matching a local name, it is better to convert the local name to the archive's internal format and search for that:
// open the zip wx.ArchiveInput in("test.zip"); // convert the local name we are looking for into the internal format wxString name = in.GetInternalName(localname); // call GetNextEntry() until the required internal name is found for(wx.ArchiveEntry entry=in.GetNextEntry(); entry != null && entry.InternalName != name; entry=in.GetNextEntry()) { } if (entry != null) { // read the entry's data... }
To access several entries randomly, it is most efficient to transfer the entire catalogue of entries to a container such as a Hashtable then entries looked up by name can be opened using the wx.ArchiveInput.OpenEntry()
method.
Hashtable catalogue=new Hashtable(); // open the zip wx.ArchiveInput in("test.zip"); // load the zip catalog for(wx.ArchiveEntry entry=in.GetNextEntry(); entry != null; entry=in.GetNextEntry()) { catalogue.Add(entry.InternalName, entry); } // open an entry by name if (catalogue.ContainsKey(in.GetInternalName(localname))) { in.OpenEntry(catalogue[in.GetInternalName(localname)]); StreamReader reader=new StreamReader(in.In); // ... now read entry's data }
To open more than one entry simultaneously you need more than one underlying stream on the same archive:
// opening another entry without closing the first requires another // input stream for the same file wxArchiveInput in2(_T("test.zip")); if (catalogue.ContainsKey(in2.GetInternalName(localname))) zip2.OpenEntry(catalogue[in2.GetInternalName(localname))]);