推薦使用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 編輯過