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

如何在C#中检测文件是否已完全移动至目标文件夹?

针对文件夹监控PDF压缩工具的文件未完全写入问题优化方案

问题背景

开发了一款Windows文件夹监控工具,触发条件为新文件添加,核心功能是压缩目标文件夹内的PDF文件。此前运行正常,但遇到低速网络传输大体积PDF时,工具会在文件尚未完全移入完成时被触发,引发异常。

当前初步方案逻辑:检测到PDF文件后尝试读取全部字节,失败则等待2分钟重试一次,仍失败则记录错误并忽略该文件。但原代码存在明显问题(如Timer启动后立刻停止,异步回调无法正确影响主线程逻辑),需要优化。

原方案问题分析

  1. Timer使用错误:代码中启动Timer后立刻调用Stop(),导致Elapsed事件根本不会触发,重试逻辑完全失效。
  2. 异步逻辑与单线程冲突:Elapsed回调在后台线程执行,对pdfFreeToUse的修改无法被主线程及时感知,主线程会直接return,后续压缩代码无法执行。
  3. 读取整个文件效率低:对大体积PDF使用File.ReadAllBytes会占用大量内存,且检测文件是否可用的方式过于笨重。

优化思路

  • 轻量文件可用性检测:通过尝试以独占模式打开文件来判断是否已写入完成,无需读取整个文件。
  • 同步重试机制:在单线程环境下使用同步重试+延迟,避免异步带来的线程安全问题。
  • 可配置重试策略:允许设置重试次数和间隔,适配不同网络环境。
  • 非阻塞监控(可选):若单线程阻塞影响监控,可将文件处理逻辑放入后台线程,保持监控线程持续运行。

优化后代码示例

bool pdfFreeToUse = false;
int retryCount = int.Parse(Config.ConfigExtractor("PdfRetryCount")); // 配置重试次数
int retryIntervalMs = int.Parse(Config.ConfigExtractor("PdfRetryIntervalMillisecond")); // 配置重试间隔(毫秒)

for (int i = 0; i <= retryCount; i++)
{
    try
    {
        // 尝试以独占方式打开文件,验证是否可访问
        using (FileStream fs = new FileStream(PdfPath, FileMode.Open, FileAccess.Read, FileShare.None))
        {
            pdfFreeToUse = true;
            break;
        }
    }
    catch (IOException)
    {
        // 文件被占用,等待后重试
        if (i < retryCount)
        {
            System.Threading.Thread.Sleep(retryIntervalMs);
        }
        else
        {
            // 重试次数耗尽,记录错误
            string errorMessage = $"无法访问PDF文件 {PdfName},可能被其他进程占用或已损坏。";
            EventProtocol.CreateEventLog();
            EventProtocol.WriteErrorEventLog(errorMessage);
            WriteErrorAsTxt($"{PdfPath}\\{PdfName}_Error.txt", errorMessage);
        }
    }
    catch (Exception ex)
    {
        // 其他异常直接记录
        string errorMessage = $"处理PDF文件 {PdfName} 时发生未知错误:{ex.Message}";
        EventProtocol.CreateEventLog();
        EventProtocol.WriteErrorEventLog(errorMessage);
        WriteErrorAsTxt($"{PdfPath}\\{PdfName}_Error.txt", errorMessage);
        break;
    }
}

if (!pdfFreeToUse)
{
    return; // 无法处理,终止当前流程
}

// 执行PDF压缩逻辑

额外建议

  1. 监控事件过滤:在文件夹监控时,可先过滤掉临时文件(如下载中的.tmp文件),只处理已完成写入的.pdf文件。
  2. 文件大小校验:记录文件第一次被检测到的大小,间隔一段时间后再次检查大小,若大小一致则认为写入完成。
  3. 后台线程处理:如果工具是单线程监控,可将PDF压缩和重试逻辑放入Task中执行,避免阻塞监控线程接收新的文件夹变更事件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 22:04:59