IOException происходит несмотря на синхронизацию потоков С#

У меня есть два обработчика событий, объявленных в одном классе (позвоните на 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 определяется ниже, в котором я 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. Другие файлы в папке очищаются, как ожидалось. Может ли кто-нибудь помочь? Спасибо.

0
источник поделиться
1 ответ

Есть несколько вещей, которые вам не хватает здесь:

  1. Событие, которое вы подключаете, - FileCreated. Это событие запускается (возможно, неудивительно), когда файл создается каким-то другим процессом, а не когда этот другой процесс завершил запись файла. Что происходит здесь, так это то, что ваш процесс получает уведомление, а другой процесс все еще записывает файл и имеет исключительную блокировку. Из документации:

Событие OnCreated создается, как только создается файл. Если файл копируется или переносится в наблюдаемый каталог, событие OnCreated будет немедленно поднято, за которым следует один или несколько событий OnChanged.

  1. После создания файла вы перебираете все файлы в каталоге (а не только файл, который только что был создан) и переносите все из них. Если создано несколько файлов, первый вызов события будет пытаться получить доступ к любым файлам в каталоге (параллельно, по сути), и поэтому даже если 1) не было проблемой, вы могли бы столкнуться с другим файлом записывается во время обработки события для первого.

Правильная вещь, чтобы сделать здесь, - это цикл, пока вы не сможете прочитать файл, как указано во втором ответе: Подождите, пока файл будет освобожден процессом

+3
источник

Посмотрите другие вопросы по меткам или Задайте вопрос