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

使用FileSystemWatcher监测下载文件时Created事件失效仅触发Renamed事件

问题描述

我用FileSystemWatcher监测下载的FBX文件时遇到异常:

  • 勾选Created复选框后,新文件下载到监测文件夹完全触发不了Created事件
  • 勾选Renamed复选框后,每个下载文件都会触发Renamed事件,但实际硬盘里看不到文件被重命名的操作

我的需求是监测新建的下载FBX文件,将其复制到其他文件夹后删除原文件,但目前监测功能不正常。相关代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace FileSysMon
{
    public partial class frmFileSysMon : Form
    {
        public frmFileSysMon()
        {
            InitializeComponent();
        }

        //Sample 01: Declarations.
        private string content = "";
        private string last_event_filename = "";

        //Sample 02: Close the form
        private void btnClose_Click(object sender, EventArgs e)
        {
            fileMon.EnableRaisingEvents = false;
            this.Close();
        }

        //Sample 03: Clear Text Content
        private void btnClear_Click(object sender, EventArgs e)
        {
            txtDisplay.Clear();
        }

        //Sample 04: Do it recursively
        private void chkRecursive_CheckedChanged(object sender, EventArgs e)
        {
            if (chkRecursive.Checked == true )
                fileMon.IncludeSubdirectories = true;
            else
                fileMon.IncludeSubdirectories = false;
        }

        //Sample 05: Set the Path to Spy using Folder Browser Dialog
        private void btnPickFolder_Click(object sender, EventArgs e)
        {
            if (FolderB.ShowDialog() == DialogResult.OK)
            {
                txtFolderPath.Text = FolderB.SelectedPath;
                fileMon.Path = txtFolderPath.Text;
            }
        }

        //Sample 06: Enable capturing file system events
        private void btnMonitor_Click(object sender, EventArgs e)
        {
            fileMon.Path = txtFolderPath.Text;
            fileMon.Filter = "*.fbx";
            txtDisplay.AppendText("Monitoring for fbx type files. Started at: " + DateTime.Now.ToString());
            txtDisplay.AppendText(Environment.NewLine);
            fileMon.EnableRaisingEvents = true;
        }

        //Sample 07: Enable capturing file system events
        private void txtFolderPath_TextChanged(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txtFolderPath.Text))
                chkRecursive.Enabled = false;
            else
                chkRecursive.Enabled = true;
        }

        //Sample 08: Monitor all the File Events
        private void fileMon_Changed(object sender, System.IO.FileSystemEventArgs e)
        {
            //!under_modification: Avoids repeated consecutive ourput of Files changed per file
            if (chkModified.CheckState == CheckState.Checked && last_event_filename != e.FullPath)
            {
                content = "File Changed: " + e.FullPath + Environment.NewLine;
                txtDisplay.AppendText(content);
            }
            last_event_filename = e.FullPath;
        }

        private void fileMon_Created(object sender, System.IO.FileSystemEventArgs e)
        {
            if (chkCreated.CheckState == CheckState.Checked)
            {
                content = "File Created: " + e.FullPath + Environment.NewLine;
                txtDisplay.AppendText(content);
            }
            last_event_filename = e.FullPath;
        }

        private void fileMon_Deleted(object sender, System.IO.FileSystemEventArgs e)
        {
            if (chkDeleted.CheckState == CheckState.Checked)
            {
                content = "File Deleted: " + e.FullPath + Environment.NewLine;
                txtDisplay.AppendText(content);
            }
            last_event_filename = e.FullPath;
        }

        private void fileMon_Renamed(object sender, System.IO.RenamedEventArgs e)
        {
            if (chkRenamed.CheckState == CheckState.Checked)
            {
                content = "File Renamed: New Name - " +  e.FullPath + " Old Name : " + e.OldFullPath 
                    + Environment.NewLine;
                txtDisplay.AppendText(content);
            }
            last_event_filename = e.FullPath;
        }
    }
}
原因分析与解决方案

异常原因

大多数下载工具(浏览器、迅雷等)的下载逻辑是:先创建带临时后缀(比如.part)或隐藏名称的临时文件,下载完成后再将临时文件重命名为最终的.fbx文件。这个过程对用户透明,但FileSystemWatcher会捕捉到最后的重命名操作,所以你看到Renamed事件触发;而Created事件只在临时文件创建时触发,但临时文件后缀不是.fbx,被你的fileMon.Filter = "*.fbx";规则过滤,因此无法感知。

解决办法

方法1:利用Renamed事件处理(最适配下载场景)

既然下载完成的标志是临时文件重命名为.fbx,直接监听Renamed事件即可,代码修改如下:

private void fileMon_Renamed(object sender, System.IO.RenamedEventArgs e)
{
    if (chkRenamed.CheckState == CheckState.Checked && 
        Path.GetExtension(e.FullPath).Equals(".fbx", StringComparison.OrdinalIgnoreCase))
    {
        content = "检测到下载完成的FBX文件:" + e.FullPath + Environment.NewLine;
        txtDisplay.AppendText(content);
        
        // 替换为你的目标文件夹路径
        string targetFolder = @"D:\YourTargetDirectory";
        if (!Directory.Exists(targetFolder))
        {
            Directory.CreateDirectory(targetFolder);
        }
        string destFilePath = Path.Combine(targetFolder, Path.GetFileName(e.FullPath));
        
        // 确保文件未被占用后执行复制删除
        try
        {
            File.Copy(e.FullPath, destFilePath, true);
            File.Delete(e.FullPath);
            txtDisplay.AppendText("文件已复制并删除原文件" + Environment.NewLine);
        }
        catch (IOException ex)
        {
            txtDisplay.AppendText("操作失败:" + ex.Message + Environment.NewLine);
            // 可添加重试逻辑,比如延迟2秒后再次尝试
        }
    }
    last_event_filename = e.FullPath;
}

方法2:放宽过滤规则监听Created事件(适合自定义下载场景)

如果坚持用Created事件,需要调整过滤规则并判断文件是否下载完成:

  1. 修改过滤规则:fileMon.Filter = "*.*";(或包含临时文件后缀,比如*.fbx;*.part)
  2. 在Created事件中添加文件状态判断:
private void fileMon_Created(object sender, System.IO.FileSystemEventArgs e)
{
    if (chkCreated.CheckState == CheckState.Checked)
    {
        // 延迟2秒确保文件写入完成
        Task.Delay(2000).ContinueWith(t =>
        {
            string ext = Path.GetExtension(e.FullPath).ToLower();
            if (ext == ".fbx" || ext == ".part")
            {
                try
                {
                    // 尝试独占打开文件,判断是否被占用
                    using (FileStream fs = File.Open(e.FullPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
                    {
                        if (ext == ".part") return; // 临时文件跳过,等待重命名后处理
                        
                        // 切换到UI线程更新界面
                        this.Invoke(new Action(() => 
                        {
                            content = "检测到FBX文件:" + e.FullPath + Environment.NewLine;
                            txtDisplay.AppendText(content);
                        }));
                        
                        // 执行复制删除逻辑
                        string targetFolder = @"D:\YourTargetDirectory";
                        if (!Directory.Exists(targetFolder))
                        {
                            Directory.CreateDirectory(targetFolder);
                        }
                        string destFilePath = Path.Combine(targetFolder, Path.GetFileName(e.FullPath));
                        File.Copy(e.FullPath, destFilePath, true);
                        File.Delete(e.FullPath);
                        
                        this.Invoke(new Action(() => 
                        {
                            txtDisplay.AppendText("文件已复制并删除原文件" + Environment.NewLine);
                        }));
                    }
                }
                catch (IOException)
                {
                    this.Invoke(new Action(() => 
                    {
                        txtDisplay.AppendText("文件正在下载,稍后重试" + Environment.NewLine);
                    }));
                }
            }
        });
        last_event_filename = e.FullPath;
    }
}

注意:FileSystemWatcher事件在非UI线程触发,操作UI必须用Invoke切换线程,避免报错。

额外注意事项

  • FileSystemWatcher可能因文件操作频繁丢失事件,建议结合定时器定期扫描文件夹作为补充
  • 处理文件时必须捕获异常,避免因文件被占用导致程序崩溃
  • 若需监听子文件夹,确保fileMon.IncludeSubdirectories = true已正确设置

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 21:55:20