从 zip 中提取时如何检测文件中的 CRC 错误

How to detect CRC errs in an file when extracting from a zip

我在一家拥有云基础应用程序的公司工作,该应用程序允许用户将数据文件从 PC 传输到他们的移动设备,然后再返回,允许用户在现场更新和编辑他们的文件。

我会随机 运行 解决一个问题,即在通过互联网传输文件的过程中,zip 结构被损坏并且 zip 中的随机文件会出现 crc 错误。

通常是图片,但并非总是如此。这会导致我们的软件出现问题并阻止文件加载。我编写了一个工具来扫描 zip 文件并查找并修复 zip 中 xml 文件中的错误;然而,System.IO.Compression.ZipFile.ExtractToDirectory 函数并没有抛出错误,它提取文件并将其写出。

我稍后进行的 System.IO.Compression.ZipFile.CreateFromDirectory 调用将此文件压缩,再次没有错误导致压缩仍然有 crc 错误并且仍然无法在我们的软件中打开。

这是我的常识,如何检查从 zip 中提取的文件是否存在 CRC 错误,并且在完成其他工作后不将它们放入新的 zip 中?

我已经尝试了一些东西,但没有将每种文件类型加载到某种 reader 中(zip 中可能有十几种文件类型)我什么也没得到。

P.S。我是 C# 的新手,没有接受过正式的编码培训,所以我可能会问一些愚蠢的问题,抱歉。 :D

可以找到一个例子here

好的,我尝试了建议的内容,这就是我得到的结果

使用以下代码:

//https://johnlnelson.com/tag/zip-archive-c/ using ZipArchive
string zipFile = FileName;
string extractPath = @"C:\Temp\XAP\" + xapName;
ZipArchive zipArchive = ZipFile.OpenRead(zipFile);

if (zipArchive.Entries != null && zipArchive.Entries.Count > 0)
{
foreach (ZipArchiveEntry entry in zipArchive.Entries)
{
entry.ExtractToFile(System.IO.Path.Combine(extractPath, entry.FullName));
}
}

并生成以下错误

ERROR:
System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Temp\XAP\CRC in bmp\assignmentmap.bmp'.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at System.IO.Compression.ZipFile

代码无法提取 zip 中的任何文件,而不仅仅是损坏的文件。

似乎在 .NET Framework 4.5 的 ZipArchive 中构建有问题。损坏的文件不会以任何方式发出信号。 SharpZipLib 中似乎还有另一个问题。以下示例的完整代码,包括检测 .NET Framework 的损坏:

using System;
using System.IO;
using System.IO.Compression;

using ICSharpCode.SharpZipLib.Zip;

using DotNetZipFile = System.IO.Compression.ZipFile;

namespace Whosebug_unzip_test
{
  internal static class Program
  {
    private static void Main()
    {
      Extract45Framework("CRCerror.zip", ".\Unpack_1");
      Console.WriteLine();
      Console.WriteLine();
      ExtractSharpZipLib("CRCerror.zip", ".\Unpack_2");
    }

    private static void Extract45Framework(string zipFile, string extractPath)
    {
      ZipArchive zipArchive = DotNetZipFile.OpenRead(zipFile);

      if (zipArchive.Entries != null && zipArchive.Entries.Count > 0)
      {
        Console.WriteLine("Extracting...");
        foreach (ZipArchiveEntry entry in zipArchive.Entries)
        {
          try
          {
            if (string.IsNullOrEmpty(entry.Name))
            {
              // skip directory
              continue;
            }

            string file = Path.Combine(extractPath, entry.FullName);
            string path = Path.GetDirectoryName(file);
            if (!Directory.Exists(path))
            {
              Directory.CreateDirectory(path);
            }

            Console.WriteLine(" - '" + entry.FullName + "'...");
            if (File.Exists(file))
            {
              //Console.WriteLine("   - delete previous version...");
              File.Delete(file);
            }

            entry.ExtractToFile(file);
            long length = (new FileInfo(file)).Length;
            if (entry.Length != length)
            {
              Console.WriteLine($"   - Failed to extract! Extracted only {length} out of {entry.Length} bytes");
            }
          }
          catch (Exception ex)
          {
            Console.WriteLine("   - Failed to extract: " + ex.Message);
          }
        }
      }
    }

    private static void ExtractSharpZipLib(string zipFileName, string extractPath)
    {
      using (var file = File.OpenRead(zipFileName))
      using (ZipInputStream zip = new ZipInputStream(file))
      {
        ZipEntry entry;
        try
        {
          while ((entry = zip.GetNextEntry()) != null)
          {
            SaveFile(zip, entry, extractPath);
          }
        }
        catch (Exception ex)
        {
          Console.WriteLine("   - Failed to parse zip: " + ex.Message);
        }
      }
    }

    private static void SaveFile(ZipInputStream zip, ZipEntry entry, string extractPath)
    {
      if (entry.IsDirectory)
      {
        return;
      }

      try
      {
        string file = Path.Combine(extractPath, entry.Name);
        string path = Path.GetDirectoryName(file);
        if (!Directory.Exists(path))
        {
          Directory.CreateDirectory(path);
        }

        Console.WriteLine(" - '" + entry.Name + "'...");
        if (File.Exists(file))
        {
          //Console.WriteLine("   - delete previous version...");
          File.Delete(file);
        }

        byte[] data = new byte[1024];
        long length = 0;
        using (var fs = File.OpenWrite(file))
        {
          int readLength;
          while ((readLength = zip.Read(data, 0, data.Length)) != 0)
          {
            fs.Write(data, 0, readLength);
            length += readLength;
          }
        }

        if (entry.Size != length)
        {
          Console.WriteLine($"   - Failed to extract! Extracted only {length} out of {entry.Size} bytes");
        }
      }
      catch (Exception ex)
      {
        Console.WriteLine("   - Failed to extract: " + ex.Message);
      }
    }
  }
}

应用程序输出:

Extracting...
 - 'tadd1.tx'...
 - 'assignmentmap.bmp'...
   - Failed to extract! Extracted only 34216 out of 34830 bytes
 - 'sketch.dsk'...


 - 'tadd1.tx'...
 - 'assignmentmap.bmp'...
   - Failed to extract: Index was outside the bounds of the array.
   - Failed to parse zip: Specified argument was out of the range of valid values.
Parameter name: count