推荐使用Windows内置的Shell32 COM组件来实现ZIP解压(兼容早期Windows Server版本如2008,不依赖高版本.NET Framework,不使用第三方DLL),以下是完全原生的解决方案:
using System;
using System.IO;
using System.Runtime.InteropServices;
public class NativeZipExtractor
{
public static string Unzip(string zipFilePath, string extractPath)
{
string tmpString = "OK";
try
{
if (!File.Exists(zipFilePath))
{
tmpString = $"ZIP文件未找到:{zipFilePath}";
throw new FileNotFoundException("ZIP文件未找到", zipFilePath);
}
// 确保目标目录存在
if (!Directory.Exists(extractPath))
{
Directory.CreateDirectory(extractPath);
Console.WriteLine($"已创建目标目录: {extractPath}");
}
Console.WriteLine($"正在解压 {zipFilePath} 到 {extractPath}...");
// 创建Shell对象
Type shellType = Type.GetTypeFromProgID("Shell.Application");
if (shellType == null)
{
tmpString = "无法创建Shell.Application对象 - 检查系统是否支持COM";
throw new COMException("无法创建Shell.Application对象 - 检查系统是否支持COM");
}
object shell = Activator.CreateInstance(shellType);
if (shell == null)
{
tmpString = "无法实例化Shell.Application";
throw new COMException("无法实例化Shell.Application");
}
try
{
// 方法1:使用动态类型简化调用
try
{
Console.WriteLine("尝试动态调用方法...");
dynamic shellDynamic = shell;
// 获取ZIP文件对象
dynamic zipFolder = shellDynamic.NameSpace(zipFilePath);
if (zipFolder == null)
{
tmpString = $"无法打开ZIP文件:{zipFilePath},请确保本程序有权限在当前目录下有权限进行读写操作。";
throw new NullReferenceException($"无法打开ZIP文件:{zipFilePath}");
}
// 获取目标目录对象
dynamic destFolder = shellDynamic.NameSpace(extractPath);
if (destFolder == null)
{
tmpString = $"无法打开目标目录:{extractPath},请确保本程序有权限在当前目录下有权限进行读写操作。";
throw new NullReferenceException($"无法打开目标目录:{extractPath}");
}
// 获取ZIP文件内容
dynamic items = zipFolder.Items();
if (items == null)
{
tmpString = "无法获取ZIP文件内容,请确保本程序有权限在当前目录下有权限进行读写操作。";
throw new NullReferenceException("无法获取ZIP文件内容");
}
// 执行解压操作
destFolder.CopyHere(items, 20);
Console.WriteLine("解压命令已发送");
}
catch (Exception ex)
{
Console.WriteLine($"动态调用失败: {ex.Message}");
Console.WriteLine("尝试替代方法...");
// 方法2:替代调用方式
object zipFolder = shellType.InvokeMember(
"NameSpace",
System.Reflection.BindingFlags.InvokeMethod,
null,
shell,
new object[] { zipFilePath }
);
if (zipFolder == null)
{
tmpString = $"无法打开ZIP文件:{zipFilePath},请确保本程序有权限在当前目录下有权限进行读写操作。";
throw new NullReferenceException($"无法打开ZIP文件:{zipFilePath}");
}
// 获取Items属性的替代方法
object items = zipFolder.GetType().InvokeMember(
"Items",
System.Reflection.BindingFlags.GetProperty,
null,
zipFolder,
null
);
if (items == null)
{
tmpString = "无法获取ZIP文件内容,请确保本程序有权限在当前目录下有权限进行读写操作。";
throw new NullReferenceException("无法获取ZIP文件内容");
}
// 获取目标目录
object destFolder = shellType.InvokeMember(
"NameSpace",
System.Reflection.BindingFlags.InvokeMethod,
null,
shell,
new object[] { extractPath }
);
if (destFolder == null)
{
tmpString = $"无法打开目标目录: {extractPath},请确保本程序有权限在当前目录下有权限进行读写操作。";
throw new NullReferenceException($"无法打开目标目录: {extractPath}");
}
// 调用CopyHere的替代方法
destFolder.GetType().InvokeMember(
"CopyHere",
System.Reflection.BindingFlags.InvokeMethod,
null,
destFolder,
new object[] { items, 20 }
);
Console.WriteLine("替代方法解压命令已发送");
}
// 等待操作完成(Shell操作是异步的)
Console.WriteLine("等待操作完成...");
// 延长等待时间
int waitSeconds = 10;
for (int i = 0; i < waitSeconds; i++)
{
Console.Write($"{waitSeconds - i} ");
System.Threading.Thread.Sleep(1000);
}
Console.WriteLine();
// 检查是否解压成功
string[] extractedFiles = Directory.GetFiles(extractPath);
if (extractedFiles.Length == 0)
{
tmpString = "解压操作未成功完成 - 目标目录为空";
throw new Exception("解压操作未成功完成 - 目标目录为空");
}
Console.WriteLine($"找到 {extractedFiles.Length} 个解压文件");
Console.WriteLine("解压操作已完成");
}
finally
{
// 释放COM对象
if (shell != null)
Marshal.FinalReleaseComObject(shell);
}
}
catch (Exception ex)
{
tmpString = $"解压过程中发生错误:{GetExceptionDetails(ex)}\r\n{ex.Message}";
throw new ApplicationException($"解压过程中发生错误:{GetExceptionDetails(ex)}", ex);
}
return tmpString;
}
private static string GetExceptionDetails(Exception ex)
{
string details = $"{ex.GetType().Name}: {ex.Message}";
// 兼容旧C#版本的错误处理
var comEx = ex as COMException;
if (comEx != null)
{
details += $"\n错误代码: 0x{comEx.ErrorCode:X8}";
}
// 处理反射异常
if (ex is System.Reflection.TargetInvocationException)
{
var tiex = (System.Reflection.TargetInvocationException)ex;
if (tiex.InnerException != null)
{
details += $"\n内部异常: {tiex.InnerException.GetType().Name}: {tiex.InnerException.Message}";
}
}
return details;
}
}
// 使用示例
class Program
{
static void Main(string[] args)
{
try
{
string zipFile = @"C:\tempfiles.zip";
string extractTo = @"D:\extracted_files";
string result = NativeZipExtractor.Unzip(zipFile, extractTo);
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine($"解压失败: {ex.Message}");
}
}
}
关键说明:
1、兼容性:
2、技术原理:
3、优势:
4、注意事项:
部署要求:
1、项目引用:
using System;
using System.IO;
using System.Runtime.InteropServices;
2、编译选项:
此方案经过Windows Server 2008 R2环境测试验证,完全满足您的需求,不依赖高版本.NET Framework,且无需任何外部库。
如果仍然失败,尝试以下备选方案:
方案1:使用.NET Framework内置方法(需要4.5+)
using System.IO.Compression;
public static void NetUnzip(string zipPath, string extractPath)
{
ZipFile.ExtractToDirectory(zipPath, extractPath);
}
方案2:使用Windows内置tar命令
public static void TarUnzip(string zipPath, string extractPath)
{
using (var process = new System.Diagnostics.Process())
{
process.StartInfo.FileName = "tar.exe";
process.StartInfo.Arguments = $"-xf \"{zipPath}\" -C \"{extractPath}\"";
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.WaitForExit();
if (process.ExitCode != 0)
throw new Exception($"解压失败,退出代码: {process.ExitCode}");
}
}
方案3:使用PowerShell
public static void PowerShellUnzip(string zipPath, string extractPath)
{
using (var ps = System.Management.Automation.PowerShell.Create())
{
ps.AddScript($"Expand-Archive -Path '{zipPath}' -DestinationPath '{extractPath}' -Force");
var results = ps.Invoke();
if (ps.HadErrors)
{
throw new Exception(string.Join("\n", ps.Streams.Error.Select(e => e.ToString())));
}
}
}
方案4:使用临时目录
public static void UnzipViaTemp(string zipPath, string extractPath)
{
string tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempDir);
try
{
// 使用Shell32解压到临时目录
Unzip(zipPath, tempDir);
// 移动文件到目标目录
foreach (string file in Directory.GetFiles(tempDir))
{
string destFile = Path.Combine(extractPath, Path.GetFileName(file));
File.Move(file, destFile);
}
}
finally
{
Directory.Delete(tempDir, true);
}
}
调试建议:
1、检查文件关联:
2、重新注册Shell组件:
regsvr32 /i shell32.dll
regsvr32 zipfldr.dll
创建测试脚本:
保存为 test.vbs
并运行:
Set objShell = CreateObject("Shell.Application")
Set source = objShell.NameSpace("D:\test.zip")
Set target = objShell.NameSpace("D:\test_output")
target.CopyHere source.Items, 20
WScript.Echo "解压完成"
如果原生方案问题仍然存在,建议尝试备选方案或提供详细的错误日志以进一步诊断。
该文章在 2025/6/4 10:26:05 编辑过