본문 바로가기

메모장/C#

[C# Debug] Zip 파일 압축 해제 문제 - System.IO.Compression.ZipFile.ExtractToDirectory

특정 안드로이드 기기에서 System.IO.Compression의 ZipFile.ExtractToDirectory 메소드를 이용해 Zip 파일을 압축 해재할때 Invalid parameter 오류가 뜨는 문제를 해결 방법이다.

오류 로그는 다음과 같다.

System.IO.IOException: Invalid parameter
  at System.IO.File.SetLastWriteTime (System.String path, System.DateTime lastWriteTime) [0x0002a] in :0
  at System.IO.Compression.ZipFileExtensions.ExtractToFile (System.IO.Compression.ZipArchiveEntry source, System.String destinationFileName, System.Boolean overwrite) [0x00067] in <8d4e08735b1842d0842f236ab3e206a3>:0
  at System.IO.Compression.ZipFileExtensions.ExtractToDirectory (System.IO.Compression.ZipArchive source, System.String destinationDirectoryName, System.Boolean overwrite) [0x0009d] in <8d4e08735b1842d0842f236ab3e206a3>:0
  at System.IO.Compression.ZipFile.ExtractToDirectory (System.String sourceArchiveFileName, System.String destinationDirectoryName, System.Text.Encoding entryNameEncoding, System.Boolean overwrite) [0x00017] in <8d4e08735b1842d0842f236ab3e206a3>:0
  at System.IO.Compression.ZipFile.ExtractToDirectory (System.String sourceArchiveFileName, System.String destinationDirectoryName, System.Text.Encoding entryNameEncoding) [0x00000] in <8d4e08735b1842d0842f236ab3e206a3>:0
  at System.IO.Compression.ZipFile.ExtractToDirectory (System.String sourceArchiveFileName, System.String destinationDirectoryName) [0x00000] in <8d4e08735b1842d0842f236ab3e206a3>:0

 

우선 이 오류를 해결하는데 결정적인 역할을 한 Git Issue 페이지를 링크로 남긴다.

https://github.com/xamarin/xamarin-android/issues/2005

 

ZipFile.ExtractToDirectory throws IOException · Issue #2005 · xamarin/xamarin-android

Steps to Reproduce Use System.IO.Compression.ZipFile.ExtractToDirectory to extract a ZIP archive. Expected Behavior Method executes successfully. Actual Behavior Method fails and an IOException is ...

github.com

 

해결법

이 오류는 FUSE 파일 시스템을 사용하는 특정 안드로이드 기기에서만 발생한다.

따라서 IOS, window에서는 발생하지 않고,
Android Oreo (Android 8.0) 이상의 버전에서는 FUSE 파일 시스템을 사용하지 않으므로 발생하지 않는다.

해결법은 ExtractToDirectory 메소드를 try-catch 문으로 묶어 IOException이 발생하면 

System.IO.File.SetLastWriteTime (System.String path, System.DateTime lastWriteTime)

메소드를 호출하지 않고 압축을 풀어야한다.

 

아래 코드를 첨부한다.

        try
        {
            ZipFile.ExtractToDirectory(bundlePath + FilePath, path);
        }
        catch (IOException e)
        {
            Console.WriteLine(e);

            using (var source = ZipFile.Open(bundlePath + FilePath, ZipArchiveMode.Read, null))
            {
                string fullName = Directory.CreateDirectory(path).FullName;
                int length = fullName.Length;
                if (length != 0 && (int) fullName[length - 1] != (int) Path.DirectorySeparatorChar)
                    fullName += Path.DirectorySeparatorChar.ToString();
                foreach (ZipArchiveEntry entry in source.Entries)
                {
                    string fullPath = Path.GetFullPath(Path.Combine(fullName, entry.FullName));
                    if (!fullPath.StartsWith(fullName, StringComparison.OrdinalIgnoreCase))
                        throw new IOException("IO_ExtractingResultsInOutside");
                    if (Path.GetFileName(fullPath).Length == 0)
                    {
                        if (entry.Length != 0L)
                            throw new IOException("IO_DirectoryNameWithData");
                        Directory.CreateDirectory(fullPath);
                    }
                    else
                    {
                        Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
                        FileMode mode = FileMode.Create;
                        using (var destination = (Stream) File.Open(fullPath, mode, FileAccess.Write, FileShare.None))
                        {
                            using (var stream = entry.Open())
                                stream.CopyTo(destination);
                        }
                    }
                }
            }
        }