首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET 伺服器端呼叫 RAR 壓縮/解壓縮:Process 啟動 WinRAR、登錄表取得路徑、工作目錄設定

     編輯:關於ASP.NET

Web 應用若需在伺服器端對上傳檔案進行壓縮或解壓縮,可透過 `System.Diagnostics.Process` 啟動已安裝的 WinRAR 執行檔。本文提供完整實作:從登錄表自動偵測 `WinRAR.exe` 路徑、建構命令列參數、設定隱藏視窗與工作目錄、非同步執行與錯誤處理。

前置條件

  • 伺服器已安裝 **WinRAR** (正式授權或試用版)
  • ASP.NET 執行身分 (Application Pool Identity) 擁有 `WinRAR.exe` 執行權限、目標資料夾讀寫權限
  • **安全警示**:伺服器端解壓縮使用者上傳檔案極高風險 (路徑遍歷、惡意腳本、壓縮炸彈),**生產環境強烈建議改用純 .NET 庫** (`SharpCompress`、`ZipArchive`、`SevenZipSharp`)

核心實作原理

1. 讀取登錄表 HKEY_CLASSES_ROOT\Applications\WinRAR.exe\Shell\Open\Command
   → 取得完整命令字串 (含參數佔位符 "%1")
2. 解析出 WinRAR.exe 實際路徑
3. 建構參數:
   壓縮:   a -r -ep1 "目標.rar" "來源路徑\*"
   解壓縮: x -o+ "來源.rar" "目標資料夾\"
4. ProcessStartInfo 設定:
   FileName = WinRAR路徑
   Arguments = 參數字串
   WindowStyle = Hidden
   WorkingDirectory = 作業目錄
   UseShellExecute = false (必要時)
   RedirectStandardOutput/Error = true (需捕獲輸出時)
5. Process.Start() 執行
6. 等待結束 / 非同步監控 / 處理 ExitCode

完整 ASPX + CodeBehind 範例 (C#)

ASPX 頁面

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html>
<html xmlns="https://www.w3.org/1999/xhtml">
<head runat="server">
    <title>伺服器端 RAR 壓縮/解壓縮示範</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:Button ID="btnCompress" runat="server" Text="壓縮 C:\Data\ → C:\Output\data.rar" 
                OnClick="btnCompress_Click" />
            <asp:Button ID="btnExtract" runat="server" Text="解壓縮 C:\Output\data.rar → C:\Extract\" 
                OnClick="btnExtract_Click" />
            <br /><br />
            <asp:Label ID="lblResult" runat="server" ForeColor="Green" />
        </div>
    </form>
</body>
</html>

CodeBehind

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.Win32;
using System.Web.UI;

public partial class _Default : Page
{
    protected void btnCompress_Click(object sender, EventArgs e)
    {
        ExecuteRar("a", @"C:\Output\data.rar", @"C:\Data\", "壓縮");
    }

    protected void btnExtract_Click(object sender, EventArgs e)
    {
        ExecuteRar("x", @"C:\Output\data.rar", @"C:\Extract\", "解壓縮");
    }

    private void ExecuteRar(string command, string archivePath, string targetPath, string actionName)
    {
        try
        {
            // 1. 從登錄表取得 WinRAR.exe 路徑
            string rarPath = GetWinRarPath();
            if (string.IsNullOrEmpty(rarPath) || !File.Exists(rarPath))
            {
                lblResult.Text = $"❌ 找不到 WinRAR.exe,請確認已安裝。路徑: {rarPath}";
                return;
            }

            // 2. 建構參數
            string arguments = BuildArguments(command, archivePath, targetPath);

            // 3. 設定 Process
            var psi = new ProcessStartInfo
            {
                FileName = rarPath,
                Arguments = arguments,
                WindowStyle = ProcessWindowStyle.Hidden,
                WorkingDirectory = Path.GetDirectoryName(archivePath) ?? @"C:\",
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true
            };

            // 4. 執行
            using (var proc = Process.Start(psi))
            {
                string output = proc.StandardOutput.ReadToEnd();
                string error = proc.StandardError.ReadToEnd();
                proc.WaitForExit(60000); // 60 秒逾時

                if (proc.ExitCode == 0)
                {
                    lblResult.Text = $"✅ {actionName} 成功!ExitCode: 0";
                }
                else
                {
                    lblResult.Text = $"❌ {actionName} 失敗,ExitCode: {proc.ExitCode}
Error: {error}
Output: {output}"; } } } catch (Exception ex) { lblResult.Text = $"❌ 例外: {ex.Message}"; } } private string GetWinRarPath() { // 嘗試多個登錄表位置 (32/64 位元、不同版本) string[] regPaths = { @"Applications\WinRAR.exe\Shell\Open\Command", @"WinRAR\Shell\Open\Command", @"Applications\WinRAR32.exe\Shell\Open\Command" }; foreach (var regPath in regPaths) { using (var key = Registry.ClassesRoot.OpenSubKey(regPath)) { if (key != null) { string cmd = key.GetValue("")?.ToString(); if (!string.IsNullOrEmpty(cmd)) { // 解析命令字串:"C:\Program Files\WinRAR\WinRAR.exe" "%1" var match = System.Text.RegularExpressions.Regex.Match(cmd, @"""(.*?)"""); if (match.Success && File.Exists(match.Groups[1].Value)) return match.Groups[1].Value; } } } } return null; } private string BuildArguments(string command, string archivePath, string targetPath) { // 參考 WinRAR 命令列語法 switch (command.ToLower()) { case "a": // 壓縮 // a -r -ep1 -ibck "archive.rar" "source\*" return $"-r -ep1 -ibck \"{archivePath}\" \"{targetPath}\\*\""; case "x": // 解壓縮 (保留路徑) // x -o+ -ibck "archive.rar" "dest\" return $"-o+ -ibck \"{archivePath}\" \"{targetPath}\\\""; case "e": // 解壓縮 (不保留路徑) return $"-o+ -ibck \"{archivePath}\" \"{targetPath}\\\""; default: throw new ArgumentException("不支援的命令: " + command); } } }

WinRAR 關鍵命令列參數說明

參數說明
`a`加入檔案到壓縮檔 (建立/更新)
`x`解壓縮並保留完整路徑結構
`e`解壓縮但忽略路徑 (所有檔案平鋪到目標資料夾)
`-r`遞迴子目錄
`-ep1`排除基礎目錄名稱 (避免壓縮包含完整絕對路徑)
`-o+`覆蓋既有檔案不提示
`-ibck`背景模式 (無視窗、無進度條)
`-hp[pwd]`設定密碼加密 (慎用,命令列可見)
`-v`分卷壓縮 (如 `-v100m`)
`-rr[N]`加入修復記錄

安全性強化清單 (生產環境必做)

  1. 檔案類型驗證:僅允許 `.zip`、`.rar`,檢查 Magic Number (Header Bytes) 而非副檔名
  2. 路徑遍歷防護:`Path.GetFullPath` 規範化、確保在允許根目錄下 (`Path.StartsWith(allowedRoot)`)
  3. 壓縮炸彈防護:限制解壓後總大小 (`ZipArchive` 可枚舉 Entry.Length 累加)、限制檔案數量、限制巢狀深度
  4. 惡意內容掃描:解壓後掃描 `.exe`、`.bat`、`.ps1`、`.php`、`.asp`、`.jsp` 等可執行腳本
  5. 隔離執行環境**:容器化、沙箱、唯讀檔案系統、無網路存取
  6. 資源限制:`ProcessStartInfo` 設定 `MaxWorkingSet`、逾時、CPU 親和性
  7. 稽核日誌:記錄使用者、檔案雜湊、操作類型、耗時、結果

現代化純 .NET 替代方案 (強烈推薦)

庫NuGet支援格式特色
SharpCompressSharpCompressRAR, ZIP, 7Z, TAR, GZIP, BZIP2純 managed、支援 RAR5、非同步、串流
System.IO.Compression.ZipArchive內建 (.NET Core/5+)ZIP零依賴、高效能、標準 API
SevenZipSharpSevenZipSharp7Z, ZIP, RAR, ISO, CAB...7-ZIP 封裝、需 7z.dll
ICSharpCode.SharpZipLibSharpZipLibZIP, GZIP, BZIP2, TAR經典、成熟、支援 .NET Framework
// SharpCompress 範例:解壓縮 RAR (純 .NET、無外部相依)
using SharpCompress.Archives.Rar;
using SharpCompress.Common;

using (var archive = RarArchive.Open(archivePath))
{
    foreach (var entry in archive.Entries.Where(e => !e.IsDirectory))
    {
        entry.WriteToDirectory(targetPath, new ExtractionOptions 
        { 
            ExtractFullPath = true, 
            Overwrite = true 
        });
    }
}

雖然呼叫 WinRAR 是快速整合現有壓縮流程的捷徑,但**安全風險、部署相依性、授權成本、跨平台限制**使其不適合現代雲原生應用。採用 **SharpCompress** 等純 .NET 庫,享受零部署、跨平台、可審計原始碼、無授權疑慮的優勢,才是長遠之計。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved