2009-07-20 2 views
12

Ich überwache einen Ordner auf neue Dateien und muss sie verarbeiten. Das Problem besteht darin, dass gelegentlich das Öffnen von Dateien fehlschlägt, weil das System das Kopieren nicht abgeschlossen hat.So testen Sie, ob eine Datei in .NET vollständig kopiert wird

Was ist der richtige Weg, um zu testen, ob die Datei fertig kopiert wurde?

Erläuterung: Ich habe keine Schreibrechte für den Ordner/Dateien und kann den Kopiervorgang nicht steuern (es ist der Benutzer).

+0

Gute Frage! Als ich dieses Problem hatte, habe ich gerade System.Threading.Thread.Sleep (1000) hinzugefügt, aber ich würde * gerne * eine bessere Lösung bekommen (es ist einfach so lahm ...) – Treb

+0

Hast du Lesezugriff auf die Originaldatei, was wird kopiert? –

Antwort

11

Ich denke, der einzige sichere Weg, dies zu tun ist, indem Sie versuchen, die Datei ausschließlich zu öffnen und eine bestimmte Ausnahme zu fangen.Normalerweise hasse ich Ausnahmen für normale Anwendungslogik, aber ich habe Angst, für dieses Szenario gibt es keine andere Möglichkeit (zumindest ich nicht einen noch gefunden haben):

public bool FileIsDone(string path) 
{ 
    try 
    { 
    using (File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None)) 
    { 
    } 
    } 
    catch(UnauthorizedAccessException) 
    { 
    return false; 
    } 

    return true; 
} 
0

ein Ansatz, den ich immer nehme, ist eine Datei am Ende meiner Kopie/Übertragung namens "token.txt" ohne Inhalt zu erstellen. Die Idee ist, dass diese Datei nur am Ende des Übertragungsvorgangs erstellt wird, sodass Sie diese Dateierstellung überwachen können und wenn diese Datei erstellt wird, beginnen Sie mit Ihren Dateien zu arbeiten. Vergessen Sie nicht, diese Token-Datei immer zu löschen, wenn Sie mit der Verarbeitung Ihrer Dateien beginnen.

+1

Aber wenn das Benutzerkonto nicht berechtigt ist, Dateien im Server zu löschen, dann wäre dieser Ansatz nutzlos. – rahul

+2

Denken Sie nicht, dass Extropie auf einen Kopierprozess wartet, den er selbst als Kontrolle hat. Also dann würde es keine Token-Datei geben, oder? – peSHIr

+1

Ich denke, Sie können nicht sagen, ob er ohne Prozess ohne weitere Details Zugriff/Kontrolle hat oder nicht. Es ist wie ein Brainstorming, bei dem jeder Input gibt. –

0

Sie auch Fälle wie abdecken sollten: Datei ist in Verwendung durch anderes Programm, eine Datei gelöscht wurde (Kopie war nicht erfolgreich) etc ..

Verwenden einer erweiterte Ausnahmebehandlung alle wichtigen Fälle, die auftreten könnten.

2

Nicht sicher über "den richtigen Weg", aber Sie könnten das Überwachungswerkzeug (FileSystemWatcher ich denke) verwenden, um eine interne Warteschlange zu füllen, die Sie für die verzögerte Verarbeitung verwenden. Oder noch besser: Verwenden Sie einfach eine Warteschlange, um Dateien zu platzieren, bei denen das Öffnen fehlgeschlagen ist, sodass Sie sie später erneut versuchen können.

1

Wenn Sie FileSystemWatcher verwenden, glaube ich nicht, dass es eine robuste Lösung für dieses Problem gibt. Ein Ansatz wäre später versuchen/fangen/wiederholen.

0

Es kommt darauf an, eine Wiederholungsschleife ist wahrscheinlich das Beste, was Sie tun können, wenn Sie keine Kontrolle über den Kopiervorgang haben.

Wenn Sie zu tun haben Kontrolle:

  • Wenn der Ordner lokal ist, können Sie verlangen, dass die Leute Sachen in sie sperren die Datei für den exklusiven Zugriff zu schreiben, und lassen Sie nur das Schloss, wenn sie fertig sind (die Ich denke, ist Standard für File.Copy). Auf der .Net-Seite könnten Sie eine einfache Wiederholungsschleife mit einer Abkühlungsdauer haben.
  • Alternativ können Sie die Datei in einen temporären Ordner schreiben und erst nach dem Schreiben in das Zielverzeichnis verschieben. Dies reduziert das Fenster, in dem schlechten Dinge passieren kann (es aber nicht beseitigen)
  • Wenn der Ordner ein SMB-Freigabe ist, gibt es eine Chance LockFile nicht einmal arbeiten (einige Linux-Implementierungen). In diesem Fall besteht der übliche Ansatz darin, eine Art Sperrdatei zu erstellen, die gelöscht wird, sobald die Person, die die Datei erstellt hat, fertig ist. Das Problem mit einem Lock-Datei-Ansatz ist, dass wenn Sie vergessen, es zu löschen, Sie in Schwierigkeiten geraten können.
  • Aufgrund dieser Komplikationen würde ich empfehlen, dass das Empfangen der Daten über einen WCF-Dienst oder einen Webdienst vorteilhaft sein kann, da Sie eine viel bessere Kontrolle haben.
  • 0

    Tatsächlich Rennbedingungen zu vermeiden, die Die einzige sichere Lösung besteht darin, es erneut zu versuchen.

    Wenn Sie so etwas wie:

    while (file is locked) 
        no-op() 
    process file() 
    

    Sie einen anderen Prozess zwischen dem während Wache und der Prozessdatei Aussage Springen in Gefahr. Egal, wie Ihre "Warte auf Dateiverfügbarkeit" implementiert wird, es sei denn, Sie können sicherstellen, dass Sie nach dem Entsperren als erster Prozess darauf zugreifen können. Sie können diesen ersten Benutzer möglicherweise nicht nicht sein.

    Dies ist wahrscheinlicher, dass auf den ersten Blick scheint, insbesondere wenn mehrere Personen die Datei beobachten, und insbesondere wenn sie so etwas wie den Dateisystemwächter verwenden. Natürlich ist es immer noch nicht besonders wahrscheinlich, selbst dann ...

    0

    Sind die Dateien groß?

    Vielleicht könnten Sie versuchen, eine MD5-Prüfsumme in der Datei zu berechnen?

    Wenn Sie den MD5-Hash in den Dateinamen eingeben, können Sie ihn abrufen und versuchen, die Prüfsumme für die Datei neu zu berechnen. Wenn die MD5 eine Übereinstimmung ist, könnten Sie davon ausgehen, dass die Datei fertig ist.

    byte[] md5Hash = null; 
    MD5 md5 = new MD5CryptoServiceProvider(); 
    using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) 
        md5Hash = md5.ComputeHash(fs); 
    
    StringBuilder hex = new StringBuilder(); 
    foreach (byte b in md5Hash) 
        hex.Append(b.ToString("x2")); 
    
    0

    Hier ist eine vb.net-Schleife, die ich verwende. Es wartet 2 Sekunden zwischen jeder Prüfung.

    Dim donotcopy As Boolean = True 
    While donotcopy = True 
        Dim myFile As New FileInfo("Filetocopy") 
        Dim sizeInBytes As Long = myFile.Length 
        Thread.Sleep(2000) 
        Dim myFile2 As New FileInfo("Filetocopy") 
        Dim sizeInBytes2 As Long = myFile2.Length 
        If sizeInBytes2 = sizeInBytes Then donotcopy = False 
    End While