尽管线程同步 C# 仍发生 IOException

IOException happening despite thread synchronization C#

我设置了 2 个事件处理程序,它们都在同一个 class 中声明(我们称之为 WrapperClass):一个用于将文件保存到文件夹,另一个用于将这些文件发送到网络 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 事件的文件。文件夹中的其他文件按预期被清除。有人能帮忙吗? 谢谢。

您在这里遗漏了一些东西:

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

The OnCreated event is raised as soon as a file is created. If a file is being copied or transferred into a watched directory, the OnCreated event will be raised immediately, followed by one or more OnChanged events.

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

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