3

I 'm trying to unzip a zip file that is inside another zip. When I try to get the FileStream of the second zip it gives me an error. How I could view the content? This is my code:

try
        {
            FileStream fs = File.OpenRead(location);
            ZipFile zipArchive = new ZipFile(fs);
            foreach (ZipEntry elementInsideZip in zipArchive)
            {
                String ZipArchiveName = elementInsideZip.Name;
                if (ZipArchiveName.Equals("MyZMLFile.xml"))
                {
                    // I NEED XML FILES
                    Stream zipStream = zipArchive.GetInputStream(elementInsideZip);
                    doc.Load(zipStream);
                    break;
                }
                // HERE!! I FOUND ZIP FILE
                else if (ZipArchiveName.Contains(".zip"))
                {
                    // I NEED XML FILES INSIDE THIS ZIP
                    string filePath2 = System.IO.Path.GetFullPath(ZipArchiveName);
                    ZipFile zipArchive2 = null;
                    FileStream fs2 = File.OpenRead(filePath2);// HERE I GET ERROR: Could not find a part of the path
                    zipArchive2 = new ZipFile(fs2);
                }
            }
        }
dev-masih
  • 4,188
  • 3
  • 33
  • 55
imj
  • 472
  • 1
  • 8
  • 24

2 Answers2

2

At that point, the zip archive name is not a file on disk. It is just a file inside the zip archive just like the xml files. You should GetInputStream() for this as you do for the xml files, Stream zipStream = zipArchive.GetInputStream(elementInsideZip); Then you can recurse the method to extract this zip again.

You need to extract the zip file first and then should recursively call the same function (Because that zip file can also contain a zip file):

private static void ExtractAndLoadXml(string zipFilePath, XmlDocument doc)
{
    using(FileStream fs = File.OpenRead(zipFilePath))
    {
        ExtractAndLoadXml(fs, doc);
    }
}

private static void ExtractAndLoadXml(Stream fs, XmlDocument doc)
{
    ZipFile zipArchive = new ZipFile(fs);
    foreach (ZipEntry elementInsideZip in zipArchive)
    {
        String ZipArchiveName = elementInsideZip.Name;
        if (ZipArchiveName.Equals("MyZMLFile.xml"))
        {
            Stream zipStream = zipArchive.GetInputStream(elementInsideZip);
            doc.Load(zipStream);
            break;
        }
        else if (ZipArchiveName.Contains(".zip"))
        {
            Stream zipStream = zipArchive.GetInputStream(elementInsideZip);
            string zipFileExtractPath = Path.GetTempFileName();
            FileStream extractedZipFile = File.OpenWrite(zipFileExtractPath);
            zipStream.CopyTo(extractedZipFile);
            extractedZipFile.Flush();
            extractedZipFile.Close();
            try
            {
                ExtractAndLoadXml(zipFileExtractPath, doc);
            }
            finally
            {
                File.Delete(zipFileExtractPath);
            }
        }
    }
}

public static void Main(string[] args)
{
    string location = null;
    XmlDocument xmlDocument = new XmlDocument();
    ExtractAndLoadXml(location, xmlDocument);
}
Oguz Ozgul
  • 6,809
  • 1
  • 14
  • 26
1

I'm not sure if this is possible. Let me explain:

Reading a ZIP file requires random access file IO to read the headers, the file table, the directory table, etc. A compressed ZIP (File) stream doesn't provide you with a random access stream, but with a sequential stream -- that's just the way algorithms like Deflate work.

To load a zip file in a zip file, you need to store the inner zip file somewhere first. For that you can use a temporary file or a simple MemoryStream (if it's not too big). That basically provides you with the random access requirement, thereby solving the problem.

atlaste
  • 30,418
  • 3
  • 57
  • 87