从 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
我在一家拥有云基础应用程序的公司工作,该应用程序允许用户将数据文件从 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