2017-12-22 11 views
0

Ich habe 2 Event-Handler beide innerhalb der gleichen Klasse deklariert (nennen wir es WrapperClass): eine Datei in einen Ordner zu speichern und eine andere, um diese Dateien an eine Web-API zu senden. Bei der Anwendung Hauptthread, rief ich die beiden Methoden bei Anwendung Start-up:IOException passiert trotz Thread-Synchronisation C#

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

NewFileEventHandler werden wie folgt definiert:

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

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

FileTransporter wie unten definiert ist, das ist, wo ich bin immer mit der Frage:

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); 
      } 
     }); 
    } 
} 

jedoch die Zeile:

wirft die Ausnahme:

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) 

Was ich nicht verstehe, ist, weil die lock die einzig möglichen zwei Prozesse, die diese Datei verwenden können, sind der rote Faden, die Datei und der Faden ist das Speichern, die versucht, Sende die Datei an die API. Mein Verständnis des Ereignisses FileSystemWatcher.Created ist jedoch, dass es ausgelöst wird, wenn die Erstellung der Datei abgeschlossen ist. Das bedeutet, dass der Thread, der die Datei speichert, die Datei nicht verwenden sollte, indem Sie versuchen, die Datei zu öffnen, um sie an api zu senden.

Manchmal befinden sich mehr als eine Datei im Ordner (wegen fehlender E-Mails in der Vergangenheit). Die IOException wird nur für die Datei ausgelöst, die gerade in Ordner gespeichert wurde (mit anderen Worten, die Datei, die das Ereignis FileSystemWatcher.Created ausgelöst hat. Die anderen Dateien im Ordner werden wie erwartet gelöscht. Kann jemand bitte helfen? Danke.

Antwort

3

Dort sind ein paar Dinge, die Sie hier fehlen:

  1. das Ereignis ist, das Sie Einhaken FileCreated Dieses Ereignis wird (wahrscheinlich wenig überraschend), wenn die Datei von einem anderen Prozess gefeuert nicht, wenn der andere Prozess erstellt wird. Englisch: www.doc-o-matic.com/webhelp/Tdlg.html Sie haben die Datei fertig geschrieben, was bedeutet, dass Ihr Prozess benachrichtigt wird, während der andere noch schreibt Datei, und hat eine exklusive Sperre für sie. Von the documentation:

Das OnCreated Ereignis wird so schnell angehoben, wie eine Datei erstellt wird. Wenn eine Datei kopiert oder in ein überwachtes Verzeichnis übertragen wird, wird das OnCreated-Ereignis sofort ausgelöst, gefolgt von einem oder mehreren OnChanged-Ereignissen .

  1. Nachdem die Datei erstellt wird, können Sie eine Schleife über alle Dateien im Verzeichnis (und nicht nur die Datei, die gerade erstellt wurde) und alle von ihnen transportieren. Wenn mehrere Dateien erstellt werden, versucht der erste Aufruf des Ereignisses auf alle Dateien in dem Verzeichnis zuzugreifen (parallel dazu, tatsächlich), und selbst wenn 1) kein Problem wäre, könnte es hier zu einer Kollision mit einer anderen Datei kommen geschrieben werden, während das Ereignis für das erste verarbeitet wird.

Das Recht, was hier zu tun ist, um Schleife, bis Sie in der Lage sind, die Datei zu lesen, wie hier in der zweiten Antwort angegeben: Wait for file to be freed by process

+0

Oh, ich ... Danke für die Erklärung zu sehen. Der Grund, warum ich alle Dateien durchlaufe, wenn ich sicherstellen muss, dass die letzte Datei und alle anderen Dateien, die bei vorherigen Versuchen verpasst wurden, gelöscht werden. Danke für die Erklärung, ich werde daran arbeiten. – swdon

+0

noch eine Sache, ist es in Ordnung, die Art, wie ich das Schloss benutze? Der Grund, warum ich diese Sperre gesetzt habe, ist, wenn mehrere Dateien erstellt wurden und mehr als ein Ereignis ausgelöst wurde. Ich wollte, dass das folgende Ereignis ausgelöst wird, nachdem das aktuelle Ereignis abgeschlossen wurde. – swdon

+2

Die Sperre wird das verhindern, ja ... Es gibt möglicherweise bessere Möglichkeiten, dies zu tun, aber das wird funktionieren. –