You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#控制台应用中显示文件夹解压与移动的进度条

实现C#控制台的解压与文件夹移动进度显示

一、Zip解压进度实现

ZipFile.ExtractToDirectory 本身没有内置的进度回调,想要显示解压进度,需要通过 ZipArchive 手动遍历压缩包条目,逐文件/逐字节处理并统计进度。

实现思路

  1. 先计算压缩包内所有文件的总大小(跳过目录条目)
  2. 遍历每个压缩条目,逐个解压文件
  3. 按字节块读取写入,实时累计已解压大小,计算进度百分比并输出到控制台

代码示例

using System.IO.Compression;

public static void ExtractZipWithProgress(string zipPath, string extractPath)
{
    Directory.CreateDirectory(extractPath);
    
    using var archive = ZipFile.OpenRead(zipPath);
    
    // 计算压缩包内所有文件的总大小
    long totalSize = archive.Entries.Sum(entry => entry.Length);
    long extractedSize = 0;

    foreach (var entry in archive.Entries)
    {
        if (string.IsNullOrEmpty(entry.Name))
        {
            // 处理目录条目
            Directory.CreateDirectory(Path.Combine(extractPath, entry.FullName));
            continue;
        }

        string destinationPath = Path.Combine(extractPath, entry.FullName);
        Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));

        // 按字节块解压,实时更新进度
        using var entryStream = entry.Open();
        using var fileStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write);
        
        byte[] buffer = new byte[8192];
        int bytesRead;
        while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0)
        {
            fileStream.Write(buffer, 0, bytesRead);
            extractedSize += bytesRead;
            
            // 控制台实时刷新进度(覆盖当前行)
            int progress = (int)((double)extractedSize / totalSize * 100);
            Console.Write($"\r解压进度: {progress}% ({extractedSize}/{totalSize} bytes)");
        }
    }
    Console.WriteLine("\n解压完成");
}

优化提示

如果压缩包内有大量小文件,进度更新会过于频繁,可以添加阈值(比如每累计1%进度再输出一次),减少控制台IO开销。


二、文件夹移动进度实现

文件夹移动分两种场景:同卷移动和跨卷移动。同卷移动只是修改文件系统目录项,几乎瞬间完成,无需显示进度;跨卷移动本质是复制文件+删除原文件,这个过程可以统计进度。

实现思路

  1. 判断源目录和目标目录是否在同一磁盘卷
  2. 同卷直接调用 Directory.Move;跨卷则先遍历所有文件计算总大小
  3. 逐文件按块复制,累计已复制大小并输出进度
  4. 复制完成后删除原目录

代码示例

public static void MoveDirectoryWithProgress(string sourceDir, string destDir)
{
    DriveInfo sourceDrive = new DriveInfo(Path.GetPathRoot(sourceDir));
    DriveInfo destDrive = new DriveInfo(Path.GetPathRoot(destDir));

    if (sourceDrive.Name == destDrive.Name)
    {
        // 同卷移动,无进度需求
        Directory.Move(sourceDir, destDir);
        Console.WriteLine("同卷移动完成");
        return;
    }

    // 跨卷移动:复制+删除
    Directory.CreateDirectory(destDir);
    var allFiles = Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories);
    long totalSize = allFiles.Sum(filePath => new FileInfo(filePath).Length);
    long copiedSize = 0;

    foreach (string sourceFile in allFiles)
    {
        string relativePath = Path.GetRelativePath(sourceDir, sourceFile);
        string destFile = Path.Combine(destDir, relativePath);
        Directory.CreateDirectory(Path.GetDirectoryName(destFile));

        // 按字节块复制,更新进度
        using var sourceStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read);
        using var destStream = new FileStream(destFile, FileMode.Create, FileAccess.Write);
        
        byte[] buffer = new byte[8192];
        int bytesRead;
        while ((bytesRead = sourceStream.Read(buffer, 0, buffer.Length)) > 0)
        {
            destStream.Write(buffer, 0, bytesRead);
            copiedSize += bytesRead;
            
            int progress = (int)((double)copiedSize / totalSize * 100);
            Console.Write($"\r移动进度: {progress}% ({copiedSize}/{totalSize} bytes)");
        }
    }

    // 复制完成后删除原目录
    Directory.Delete(sourceDir, true);
    Console.WriteLine("\n移动完成");
}

注意事项

  • 建议添加异常处理逻辑,比如复制失败时回滚已复制的文件
  • 缓冲区大小可根据实际场景调整(8192字节是平衡速度与内存占用的常用值)

内容的提问来源于stack exchange,提问作者Ismail Hmama

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 04:40:44