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

FileSystemWatcher监控目录上传SharePoint遇文件被占用异常求助

解决FileSystemWatcher拖拽多文件时的“文件被占用”异常

这个问题我太熟悉了!FileSystemWatcher的Created事件触发时机其实有点“急性子”——它在文件刚被创建(甚至内容还没完全写入磁盘)的时候就会通知你,这时候文件大概率还被创建它的进程(比如你拖拽文件时的Windows资源管理器)锁着,直接去读取或上传肯定会抛出System.IO.IOException。下面给你几个实用的解决方案:

1. 给上传逻辑加重试机制

最直接有效的办法就是捕捉异常后,等待一小段时间再重试,直到文件可以被访问或者达到重试上限。这里给你写个异步的重试辅助方法示例:

private async Task UploadFileWithRetry(string filePath, int maxRetries = 5, int delayMs = 500)
{
    for (int retryCount = 0; retryCount < maxRetries; retryCount++)
    {
        try
        {
            // 尝试以排他方式打开文件,确认没有被占用
            using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None))
            {
                // 执行SharePoint上传逻辑,比如传入流和文件名
                await UploadToSharePoint(fileStream, Path.GetFileName(filePath));
                return; // 成功上传就退出重试循环
            }
        }
        catch (IOException)
        {
            // 如果是最后一次重试,就抛出异常;否则等待后重试
            if (retryCount == maxRetries - 1)
                throw;
            await Task.Delay(delayMs);
        }
    }
}

你可以在Created事件的处理方法里直接调用这个重试方法,不用同步阻塞事件线程。

2. 结合Changed事件确认文件就绪

Created事件只触发一次,但Changed事件会在文件内容写入过程中多次触发(比如文件大小变化时)。你可以结合这两个事件,或者优先监听Changed事件来判断文件是否已经完全写入。

比如可以记录每个文件的最后修改时间和大小,当连续两次触发Changed事件时,文件的大小和修改时间都没有变化,就说明文件已经就绪了:

private readonly Dictionary<string, (DateTime LastModified, long FileSize)> _fileStatus = new Dictionary<string, (DateTime, long)>();

private async void OnFileChanged(object sender, FileSystemEventArgs e)
{
    var fileInfo = new FileInfo(e.FullPath);
    if (!fileInfo.Exists) return;

    var currentStatus = (fileInfo.LastWriteTimeUtc, fileInfo.Length);
    
    if (_fileStatus.TryGetValue(e.FullPath, out var lastStatus))
    {
        // 如果两次状态一致,说明文件已经写完
        if (lastStatus == currentStatus)
        {
            _fileStatus.Remove(e.FullPath);
            await UploadFileWithRetry(e.FullPath);
            return;
        }
    }
    _fileStatus[e.FullPath] = currentStatus;
}

3. 提前检查文件是否可访问

在上传前先写个辅助方法,检查文件是否能被正常打开,避免直接抛出异常:

private bool IsFileAccessible(string filePath)
{
    try
    {
        using (var stream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        {
            return stream.Length > 0; // 额外确保文件不是空的
        }
    }
    catch (IOException)
    {
        return false;
    }
}

然后在处理事件时,循环调用这个方法,直到返回true再执行上传:

private async void OnFileCreated(object sender, FileSystemEventArgs e)
{
    while (!IsFileAccessible(e.FullPath))
    {
        await Task.Delay(300);
    }
    await UploadToSharePoint(e.FullPath);
}

额外注意事项

  • 不要在FileSystemWatcher的事件处理线程里做耗时的上传操作,最好把任务放到异步队列里处理,避免阻塞事件线程导致后续事件堆积。
  • 拖拽多个文件时,Windows资源管理器可能会逐个锁定文件,所以重试间隔不要设置得太短(300-500毫秒比较合适)。
  • 处理文件前一定要先检查文件是否还存在,避免文件在触发事件后被删除或重命名的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:52:53