【问题标题】:IOException happening despite thread synchronization C#尽管线程同步 C# 仍发生 IOException
【发布时间】:2018-06-04 17:49:05
【问题描述】:

我设置了 2 个事件处理程序,它们都在同一个类中声明(我们称之为 WrapperClass):一个用于将文件保存到文件夹,另一个用于将这些文件发送到 Web api。在应用程序主线程中,我在应用程序启动时调用了这两个方法:

// save file to folder:
NewFileEventHandler();
// send file to api:
FileTransporter();

NewFileEventHandler定义如下:

public void NewFileEventHandler()
{
    SomeEventClass.NewFileEvent +=
         new FileEventHandler(SaveFileToFolder);
}

private void SaveFileToFolder(File file)
{
    FileHelper.SaveFileToFolder(file);
}

FileTransporter 定义如下,这是我遇到问题的地方:

public void FileTransporter()
{
     FileSystemWatcher newFileWatcher = new FileSystemWatcher();
     newFileWatcher.Path = ConfigurationHelper.applicationRootDirectory;
     newFileWatcher.Filter = "*.txt";
     newFileWatcher.Created +=
     new FileSystemEventHandler(TransportFile);
     newFileWatcher.EnableRaisingEvents = true;
}

And the `TransportFile()` is given below:

private void TransportFile(object source, FileSystemEventArgs e)
{
    lock (_fileTransportLock)
    {
         string[] files = new string[] { };
         files = Directory.GetFiles(ConfigurationHelper.applicationRootDirectory, "*.txt", SearchOption.TopDirectoryOnly);
         Parallel.ForEach(files, (currentFile) =>
         {
             bool isHttpTransferSuccess = false;

             isHttpTransferSuccess = FileHelper.SendFileToApi(userid, currentFile);
             if (isHttpTransferSuccess)
             {
                 File.Delete(currentFile);
             }
        });
     }
}

但是,这行:

抛出异常:

System.IO.IOException: The process cannot access the file 'C:\Users\myapp\file.txt' because it is being used by another process.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at System.IO.File.Open(String path, FileMode mode)
   at FileHelper.SendFileToApi(String userId, String fileLocation)

我不明白的是,由于lock,唯一可能使用此文件的两个进程是保存文件的线程和尝试将文件发送到 api 的线程。但是,我对FileSystemWatcher.Created 事件的理解是,它在文件创建完成时触发。这意味着,在 TransportFile() 方法尝试打开文件以将其发送到 api 时,保存文件的线程不应该正在使用该文件。

有时文件夹中有多个文件(由于过去错过了电子邮件)。 IOException 仅针对刚刚保存到文件夹的文件(换句话说,引发FileSystemWatcher.Created 事件的文件。文件夹中的其他文件按预期清除。有人可以帮忙吗?谢谢。

【问题讨论】:

    标签: c# multithreading locking ioexception


    【解决方案1】:

    这里缺少一些东西:

    1. 您要挂钩的事件是FileCreated。当文件由其他进程创建时(可能并不奇怪)会触发此事件,不是当其他进程完成写入文件时。这里发生的情况是,您的进程在另一个进程仍在写入文件时收到通知,并且对其具有排他锁。来自the documentation

    创建文件后立即引发 OnCreated 事件。如果一个文件 正在被复制或传输到监视目录中,OnCreated 事件将立即引发,然后是一个或多个 OnChanged 事件。

    1. 创建文件后,循环遍历目录中的所有文件(不仅仅是刚刚创建的文件)并传输所有文件。如果创建了多个文件,则对事件的第一次调用将尝试访问目录中的任何文件(实际上是并行的),因此即使 1) 不是问题,您也可能在此处与另一个文件发生冲突在处理第一个事件时被写入。

    此处正确的做法是循环直到您能够读取文件,如此处第二个答案中所述:Wait for file to be freed by process

    【讨论】:

    • 哦,我明白了...感谢您的解释。我循环遍历所有文件的原因是因为我需要确保清除最新文件和之前尝试中遗漏的任何其他文件。谢谢你的解释,我会努力的。
    • 还有一件事,可以吗,我使用锁的方式?我设置该锁定的原因是如果创建了多个文件并且引发了多个事件,我希望在完成当前事件后处理引发的后续事件。
    • 锁会阻止这种情况,是的......有可能更好的方法来做到这一点,但这会奏效。
    • 如果你有时间,请给我一些更好的方法 :) 谢谢你到目前为止的帮助,我已经可以处理这些信息了。
    • 因为看起来您是在自己编写文件,所以我只是在文件写入后调用上传方法(在SaveFileToFolder 方法中)。之后,您可以扫描目录。而不是为 FSW 烦恼。
    猜你喜欢
    • 2020-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多