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

如何实现C#4.5控制台程序在3个文件上传完成后自动启动?

实现文件全量上传后的自动导入方案

嗨,针对你遇到的“三个文件全部上传完成后才触发导入程序”的需求,我给你整理了两种靠谱的解决方案,都是基于你现有的技术栈(C# 4.5 + SQL Server 2014)来实现的:

方案一:改进FileSystemWatcher,添加延迟检查与文件完整性验证

FileSystemWatcher本身确实会在文件开始创建时就触发事件,但我们可以通过两个关键优化来解决问题:

  • 延迟检查:给文件上传留足写入时间,避免触发时文件还在传输中
  • 文件就绪验证:确认文件已经完全写入,无法被其他进程占用

核心实现步骤

  1. 从app.config读取配置参数
  2. 配置FileSystemWatcher监听目标文件夹的创建和大小变化事件
  3. 事件触发后延迟几秒,再检查三个文件是否都存在且就绪
  4. 满足条件时启动导入程序,完成后归档文件避免重复处理

代码示例

using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;

class AutoImportWatcher
{
    static void Main(string[] args)
    {
        var sourceFolder = ConfigurationManager.AppSettings["SourceFolder"];
        if (!Directory.Exists(sourceFolder))
        {
            Console.WriteLine($"Source folder {sourceFolder} does not exist!");
            return;
        }

        // 初始化文件监视器
        var watcher = new FileSystemWatcher(sourceFolder)
        {
            IncludeSubdirectories = false,
            NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size // 监听文件名和大小变化
        };

        // 绑定事件
        watcher.Created += OnFileChanged;
        watcher.Changed += OnFileChanged;
        watcher.EnableRaisingEvents = true;

        Console.WriteLine($"Watching folder: {sourceFolder}");
        Console.WriteLine("Press Enter to exit...");
        Console.ReadLine();

        watcher.Dispose();
    }

    private static async void OnFileChanged(object sender, FileSystemEventArgs e)
    {
        // 延迟5秒,给文件上传留时间(可根据文件大小调整)
        await Task.Delay(TimeSpan.FromSeconds(5));
        CheckAndRunImport(sender);
    }

    private static void CheckAndRunImport(object sender)
    {
        var watcher = (FileSystemWatcher)sender;
        var sourceFolder = watcher.Path;
        var requiredFiles = new[]
        {
            ConfigurationManager.AppSettings["DisbursementFile"],
            ConfigurationManager.AppSettings["EmployeeFile"],
            ConfigurationManager.AppSettings["AmountFile"]
        };

        // 检查所有文件是否存在且已就绪
        bool allFilesReady = requiredFiles.All(file =>
        {
            string filePath = Path.Combine(sourceFolder, file);
            return File.Exists(filePath) && IsFileFullyUploaded(filePath);
        });

        if (allFilesReady)
        {
            // 临时关闭监视器,避免重复触发
            watcher.EnableRaisingEvents = false;

            try
            {
                Console.WriteLine("All files detected, starting import...");
                // 启动你的导入控制台程序
                Process.Start(@"Path\To\Your\ImportProgram.exe");

                // 归档文件,防止重复处理
                string archiveFolder = ConfigurationManager.AppSettings["ArchiveFolder"];
                if (!Directory.Exists(archiveFolder))
                    Directory.CreateDirectory(archiveFolder);

                foreach (var file in requiredFiles)
                {
                    string sourcePath = Path.Combine(sourceFolder, file);
                    string archivePath = Path.Combine(archiveFolder, $"{DateTime.Now:yyyyMMddHHmmss}_{file}");
                    File.Move(sourcePath, archivePath);
                    Console.WriteLine($"Archived file: {archivePath}");
                }

                // 记录日志
                WriteLog("Import completed successfully, files archived.");
            }
            catch (Exception ex)
            {
                WriteLog($"Import failed: {ex.Message}");
            }
            finally
            {
                // 重新开启监视器
                watcher.EnableRaisingEvents = true;
            }
        }
    }

    // 判断文件是否完全上传(能否被独占打开)
    private static bool IsFileFullyUploaded(string filePath)
    {
        try
        {
            using (var stream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
            {
                return true;
            }
        }
        catch (IOException)
        {
            // 文件被占用,说明还在上传
            return false;
        }
    }

    // 写入日志
    private static void WriteLog(string message)
    {
        string logPath = ConfigurationManager.AppSettings["LogFile"];
        string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}{Environment.NewLine}";
        File.AppendAllText(logPath, logEntry);
    }
}

方案二:定时扫描文件夹(更简单稳定的备选)

如果觉得FileSystemWatcher的事件触发逻辑太敏感,可以用定时扫描的方式,每隔一段时间检查目标文件夹是否满足条件:

代码示例

using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Threading;
using System.Diagnostics;

class AutoImportScanner
{
    static void Main(string[] args)
    {
        var scanInterval = TimeSpan.FromMinutes(1); // 每分钟扫描一次,可调整
        var timer = new Timer(_ => CheckAndRunImport(), null, TimeSpan.Zero, scanInterval);

        Console.WriteLine("Auto import scanner started. Press Enter to exit...");
        Console.ReadLine();
        timer.Dispose();
    }

    private static void CheckAndRunImport()
    {
        var sourceFolder = ConfigurationManager.AppSettings["SourceFolder"];
        var requiredFiles = new[]
        {
            ConfigurationManager.AppSettings["DisbursementFile"],
            ConfigurationManager.AppSettings["EmployeeFile"],
            ConfigurationManager.AppSettings["AmountFile"]
        };

        bool allFilesReady = requiredFiles.All(file =>
        {
            string filePath = Path.Combine(sourceFolder, file);
            return File.Exists(filePath) && IsFileFullyUploaded(filePath);
        });

        if (allFilesReady)
        {
            try
            {
                Console.WriteLine("All files detected, starting import...");
                Process.Start(@"Path\To\Your\ImportProgram.exe");

                // 归档文件
                string archiveFolder = ConfigurationManager.AppSettings["ArchiveFolder"];
                if (!Directory.Exists(archiveFolder))
                    Directory.CreateDirectory(archiveFolder);

                foreach (var file in requiredFiles)
                {
                    string sourcePath = Path.Combine(sourceFolder, file);
                    string archivePath = Path.Combine(archiveFolder, $"{DateTime.Now:yyyyMMddHHmmss}_{file}");
                    File.Move(sourcePath, archivePath);
                }

                WriteLog("Import completed successfully.");
            }
            catch (Exception ex)
            {
                WriteLog($"Import error: {ex.Message}");
            }
        }
    }

    // 复用之前的IsFileFullyUploaded和WriteLog方法
    private static bool IsFileFullyUploaded(string filePath) 
    {
        try
        {
            using (var stream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
            {
                return true;
            }
        }
        catch (IOException)
        {
            return false;
        }
    }
    
    private static void WriteLog(string message)
    {
        string logPath = ConfigurationManager.AppSettings["LogFile"];
        string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}{Environment.NewLine}";
        File.AppendAllText(logPath, logEntry);
    }
}

关键注意事项

  • 避免重复处理:一定要在导入完成后将文件移到Archive文件夹,或者重命名(比如加.processed后缀)
  • 日志记录:严格记录每一步操作,方便后续排查问题
  • 权限配置:确保运行自动程序的账户有目标文件夹的读写权限,以及启动导入程序的权限
  • 延迟时间调整:如果你的文件很大,需要适当延长延迟时间,避免文件还在写入时就触发导入

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:03:22