2010-09-29 17 views
12
var fsw = new FileSystemWatcher(sPath, "*.PPF"); 
fsw.NotifyFilter = NotifyFilters.FileName; 
fsw.IncludeSubdirectories = true; 
fsw.Created += FswCreated; 
fsw.EnableRaisingEvents = true; 

static void FswCreated(object sender, FileSystemEventArgs e) 
{ 
    string sFile = e.FullPath; 
    string[] arrLines = File.ReadAllLines(sFile); 
} 

Dies schlägt mit großen Dateien fehl, weil der Prozess nicht mit dem Schreiben der Datei abgeschlossen ist. Die Datei wird über das Netzwerk kopiert, daher kenne ich die Größe der Datei nicht. Welche Art von Synchronisation ist erforderlich, um dies robust zu machen?Filesystem Watcher und große Dateien

+0

schlägt fehl, wie? Welche Ausnahme? –

Antwort

27

Lösung auf Stackoverflow gefunden und etwas modifiziert.

static bool IsFileLocked(FileInfo file) 
{ 
    FileStream stream = null; 

    try 
    { 
     stream = file.Open(FileMode.Open, 
       FileAccess.ReadWrite, FileShare.None); 
    } 
    catch (IOException) 
    { 
     //the file is unavailable because it is: 
     //still being written to 
     //or being processed by another thread 
     //or does not exist (has already been processed) 
     return true; 
    } 
    finally 
    { 
     if (stream != null) 
      stream.Close(); 
    } 

    //file is not locked 
    return false; 
} 

static void FswCreated(object sender, FileSystemEventArgs e) 
{ 
    string sFile = e.FullPath; 

    Console.WriteLine("processing file : " + sFile); 

    // Wait if file is still open 
    FileInfo fileInfo = new FileInfo(sFile); 
    while(IsFileLocked(fileInfo)) 
    { 
     Thread.Sleep(500); 
    } 

    string[] arrLines = File.ReadAllLines(sFile); 
} 
+0

danke für die formatierung meines artikels. Wo finde ich das richtige Format für meine zukünftigen Fragen? – NickD

+0

Großartig, aber wenn Datei schreibgeschützt ist, wird es fehlschlagen. Sie können die Datei mit dem Zugriffsmodus FileAccess.Read öffnen. – electricalbah

+0

wahr, thx für Hinweise. – NickD

0

Einfach in Ihrem fswCreated, schlafen Sie für etwa 1/2 Sekunden mit Thread.Sleep(500), wenn das möglich ist. Das sollte Ihnen die Zeit geben, die der Computer benötigt, um das Schreiben der Datei abzuschließen.

Natürlich, für langsamere Festplatten kann dies oder kann genug Zeit.

+0

dies funktioniert nicht, wenn die Datei sehr groß ist wie in GBs. die lösung ist es zu versuchen, lesen sie die datei im filestream und handhabung die io ausnahme von Thread.Sleep und die versuchen, die datei zu lesen überprüfen meine unter antwort – Thakur

4

Verwenden Sie die DelayedFileSystemWatcher.cs Klasse http://blogs.msdn.com/b/ahamza/archive/2006/02/06/526222.aspx

und dann diesen Code. Überprüfen Sie den Eventhandler PrintFileSystemEventHandler. Es versucht, die Datei im Dateistream zu lesen, und wenn ein Fehler auftritt, nimmt sie an, dass die Datei noch liest, so dass sie auf ein Intervall wartet (in diesem Beispiel 2 Sekunden) und dann erneut versucht. Überprüfen Sie die CONVERSION: Label

static void Main(string[] args) 
    { 
     DelayedFileSystemWatcher dfw = new DelayedFileSystemWatcher(@"C:\\Test", "*.*"); 
     dfw.Changed += new FileSystemEventHandler(Program.FileSystemEventHandlerMethod); 
     dfw.Created += new FileSystemEventHandler(Program.FileSystemEventHandlerMethod); 
     dfw.Deleted += new FileSystemEventHandler(Program.FileSystemEventHandlerMethod); 
     dfw.Error += new ErrorEventHandler(Program.ErrorEventHandlerMethod); 
     dfw.Renamed += new RenamedEventHandler(Program.RenamedEventHandlerMethod); 

     dfw.IncludeSubdirectories = true; 
     dfw.ConsolidationInterval = 1000; 
     dfw.EnableRaisingEvents = true; 
     Console.WriteLine("Press \'q\' to quit the sample."); 
     while (Console.Read() != 'q') ; 
     //System.Threading.Thread.Sleep(60000); 
     dfw.Dispose(); 
    } 
    private static void FileSystemEventHandlerMethod(object sender, FileSystemEventArgs e) 
    { 
     PrintFileSystemEventHandler(e); 
     System.Console.WriteLine(); 
    } 

    private static void ErrorEventHandlerMethod(object sender, ErrorEventArgs e) 
    { 
     System.Console.WriteLine(e.GetException().Message); 
     System.Console.WriteLine(); 
    } 

    private static void RenamedEventHandlerMethod(object sender, RenamedEventArgs e) 
    { 
     PrintRenamedEventHandler(e); 
     System.Console.WriteLine(); 
    } 

    private static void PrintFileSystemEventHandler(FileSystemEventArgs e) 
    { 

    CONVERSION: 
     try 
     { 

      if (e.ChangeType != WatcherChangeTypes.Deleted) 
      { 
       if (!isFolder(e.FullPath) && isFile(e.FullPath)) 
       { 
        FileStream fs = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.None); 
        fs.Close(); 
       } 

      } 
      System.Console.WriteLine(e.Name + " " + e.FullPath + " " + e.ChangeType); 

     } 
     catch (System.IO.IOException) 
     { 
      Console.WriteLine("There was an IOException error or File is still copying. Retrying in 2 seconds..."); 
      System.Threading.Thread.Sleep(2000); 
      goto CONVERSION; 
     } 



     //System.Console.WriteLine(e.Name); 
     //System.Console.WriteLine(e.FullPath); 
     //System.Console.WriteLine(e.ChangeType); 
    } 

    private static bool isFolder(string strPath) 
    { 

     bool isFolderExist = false; 
     try 
     { 
      isFolderExist = Directory.Exists(strPath); 
     } 
     catch 
     { 
      isFolderExist = false; 
     } 
     return isFolderExist; 
    } 

    private static bool isFile(string strPath) 
    { 

     bool isFileExist = false; 
     try 
     { 
      isFileExist = File.Exists(strPath); 
     } 
     catch 
     { 
      isFileExist = false; 
     } 
     return isFileExist; 
    } 


    private static void PrintRenamedEventHandler(RenamedEventArgs e) 
    { 
     PrintFileSystemEventHandler(e); 
     System.Console.WriteLine(e.OldName); 
     System.Console.WriteLine(e.OldFullPath); 
    } 

ich nicht den Link zu dem Projekt haben. aber das wird helfen.

+1

Ich kann ein 'goto' dort sehen :) –

1

AFAIK Sie werden nicht benachrichtigt, sobald die Kopie fertig ist, können Sie einen Wiederholungsmechanismus implementieren.
Wenn Sie eine Scherverletzung erhalten, lösen Sie einfach einen Timer aus, um den Vorgang in X Sekunden zu wiederholen.
Die zweite Wiederholung sollte nach X * 2 Sekunden und so weiter sein (mit einigen Einschränkungen natürlich).

2

Ich unterstütze die von Shay Erlichmen akzeptierte Lösung. Aber wie a) Sie wan't kann die Datei mit Zugriffsmodus FileAccess.Read zu öffnen, einhüllen its a die Datei einige lustige Erweiterung haben einige Programme nur

b), während das Herunterladen, lesen Datei und wenn sie abgeschlossen sind, Die Erweiterung wird sich ändern, und obwohl die Datei abgeschlossen wäre, wird die Datei nicht gefunden.

So behandeln Sie die Ausnahmen, und auch file.renamed Ereignis abonnieren