简体   繁体   中英

C# ZipArchive Illegal characters in path

Given the following code:

using (var data = new MemoryStream(bytes))
using(var archive = new ZipArchive(data))
{
    foreach (var entry in archive.Entries)
    {
        entry.FullName.Log();
    }
    ...

The exception thrown is:

Illegal characters in path.

On the foreach line.

How do I work out which the affected entry is? Whenever I try to access the entries it throws the exception. It appears that this specific archive is created from a Mac as it contains the _MACOSX folder.

The stack trace:

[ArgumentException: Illegal characters in path.]
   System.IO.Path.CheckInvalidPathChars(String path, Boolean checkAdditional) +14351233
   System.IO.Path.GetFileName(String path) +29
   System.IO.Compression.ZipHelper.EndsWithDirChar(String test) +9
   System.IO.Compression.ZipArchiveEntry.set_FullName(String value) +93
   System.IO.Compression.ZipArchiveEntry..ctor(ZipArchive archive, ZipCentralDirectoryFileHeader cd) +228
   System.IO.Compression.ZipArchive.ReadCentralDirectory() +172
   System.IO.Compression.ZipArchive.get_Entries() +36

Your exception is being thrown because ZipArchive.Entries attempts to read the zip central directory in order to construct a ZipArchiveEntry for each entry. The ZipArchiveEntry constructor is calling Path.GetFileName , which calls Path.CheckInvalidPathChars , which throws if the path contains \0 .

Although an exception part-way through reading the central directory will leave the ZipArchive with a partially-populated list of entries, there doesn't seem to be any way to read it without triggering a read of the central directory again, unless you use the debugger / reflection to read _entries or _entriesCollection . This will tell you which entries succeeded, which might narrow down the failing one a bit. If you're going to these lengths, debugging into the .Entries call would tell you exactly which entry is failing.

It looks like a related issue with paths being treated differently across different platforms was recognised in 2015 , and as part of that a change was made to get the file name without calling Path.CheckInvalidPathChars , which should avoid the issue (you'll still get an exception if you try to write this entry to a file on Windows, but at least .Entries shouldn't throw). Unfortuatenly this was only introduced in .NET Core however.

Agree with comments. Are you sure your file is intact and originates from a compatible platform.. What happens if you open your Archive with eg WinRar?

I tested below code before and successfully modified it using a memory stream like you do, and I am sure your version should work as well..

    [Test]
    public void TestZipper()
    {
        using (var dataFromFile = new FileStream("d:\\lx\\MyZip.ZIP", FileMode.Open))
        {
            var dataInMemory = new MemoryStream();
            dataFromFile.CopyTo(dataInMemory);
            using (var archive = new ZipArchive(dataInMemory))
            {
                foreach (var entry in archive.Entries)
                {
                    Debug.WriteLine(entry.FullName);
                }
                Assert.That(MyZipListIsComplete(archive.Entries));
            }
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM