C# FileSystemWatcher线程和计时问题

C# FileSystemWatcher线程和计时问题,c#,multithreading,C#,Multithreading,我们有一个将员工W2打印为PDF的应用程序。不幸的是,该应用程序没有密码保护PDF 我已经编写了一个服务,它使用FileSystemWatcher在创建PDF时查找PDF。然后它获取PDF并使用ASPose.PDF向PDF添加密码和加密 我的第一个问题是时机。在FileSystemWatcher调用事件处理程序通知我新创建的文件后,我不得不在代码中嵌入Thread.Sleep2000。如果我不这样做,我会遇到一个问题,ASPose.PDF无法获得它需要的文件访问权限,因为它正在使用中-显然创建应

我们有一个将员工W2打印为PDF的应用程序。不幸的是,该应用程序没有密码保护PDF

我已经编写了一个服务,它使用FileSystemWatcher在创建PDF时查找PDF。然后它获取PDF并使用ASPose.PDF向PDF添加密码和加密

我的第一个问题是时机。在FileSystemWatcher调用事件处理程序通知我新创建的文件后,我不得不在代码中嵌入Thread.Sleep2000。如果我不这样做,我会遇到一个问题,ASPose.PDF无法获得它需要的文件访问权限,因为它正在使用中-显然创建应用程序尚未发布。这是一个有点难闻的解决方案,如果有更好的处理方法的话,我希望得到一些意见

然而,我更大的问题是,我希望通过任务实现异步处理,以便在生成数千个文件时获得更好的性能。在处理任务和线程方面,我几乎是个新手

这就是我计划做的任务。。。这是正确的方法吗

public class W2PDFEncryptionService : ServiceBase
{
    private FileSystemWatcher _watcher = null;
    private Aspose.Pdf.License _license = null;
    private string _connectionString = "";
    private string _targetDir = "";
    private string _masterPassword = "";
    private const int SLEEPTIME = 2000;
    private const string PASSFORMAT = "[{0}!{1}]";

    protected override void OnStart(string[] args)
    {
        base.OnStart(args);

        ReadAppSettings();

        //Log current run state
        _builder.Clear();
        _builder.AppendLine("Sarting Service");
        _builder.AppendLine("   Monitor Directory: " + _targetDir);
        _builder.AppendLine("   SQL Connection: " + _connectionString);
        this.EventLog.WriteEntry(_builder.ToString());

        ConfigureFileWatcher();
    }

    private void ConfigureFileWatcher()
    {
        // _watcher is a private property of the service
        _watcher = new FileSystemWatcher(_targetDir); 
        _watcher.IncludeSubdirectories = true;
        _watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.CreationTime;

        _watcher.Created += new FileSystemEventHandler(OnChanged);
        _watcher.Renamed += new RenamedEventHandler(OnRename);

        _watcher.EnableRaisingEvents = true;
    }

    private void OnRename(object sender, RenamedEventArgs e)
    {
        Task task = ProcessFile(e.FullPath, "PDF Renamed - " + e.OldName + " to " + e.Name + " in folder " + Path.GetDirectoryName(e.FullPath));
    }

    private void OnChanged(object sender, FileSystemEventArgs e)
    {
        Task task = ProcessFile(e.FullPath, "PDF Created - " + e.Name + " in folder " + Path.GetDirectoryName(e.FullPath));
    }

    private async Task ProcessFile(string filename, string logtext)
    {
        //Pause for two seconds to ensure file is not in use
        //Thread.Sleep(SLEEPTIME);
        Task.Delay(SLEEPTIME);

        EncryptFile(filename, _userPassword); //this is where ASPose.PDF is used
    }
似乎这将允许服务为创建或重命名的每个PDF启动一个新的处理/加密任务

诚然,每个线程都必须创建自己的ASPose.PDF实例,以便处理其文件以避免锁定iUse

我有什么遗漏吗


另一方面,我想得更多了,似乎我没有办法解释由于未完成的线程而暂停或停止的服务

如果您没有权限,您可以继续尝试在指数后退的情况下打开文件;您无法立即打开它的原因是另一个程序正在忙于写入文件。文件第一次打开时,而不是最后关闭时,“创建”事件将立即触发。这仍然是一个解决办法,但它比等待固定的时间更正确。你可以看看。特别是关于查找更改的文件而不是创建的文件。此外,与其为每个文件启动新任务,不如让事件将文件名放在BlockingCollection的队列中。具有一个或多个长期运行的任务,这些任务从该队列中读取并处理项目。这样,您可以限制未完成任务的数量,并且可以更轻松地关闭它们。当收到FSW通知时,您几乎可以指望无法打开该文件。因为某个程序刚刚更改了文件,所以它还没有关闭它。使用线程来读取数千个文件是一个非常糟糕的主意,很可能吞吐量会显著降低。仅仅是强迫磁盘驱动器读卡器磁头不断地来回跳跃。汉斯,那么你将如何处理像我这样的情况,即我们需要在创建这些文件时对其进行加密?你会像Jim提到的那样使用BlockingCollection和一个长时间运行的任务吗?我会使用提供加密的内置操作系统功能。无需代码,对编写文件的应用程序完全不透明,当敏感数据泄露时,应该责怪其他人。Windows上的Bitlocker。