Wenn eine Datei FileSystemWatcher_Created
in einem Verzeichnis erstellt ( ) wird, kopiere ich sie in ein anderes. Aber wenn ich ein großes (> 10 MB) Datei erstellen kann es die Datei kopieren, weil es das Kopieren beginnt bereits, wenn die Datei noch nicht fertig zu schaffen , ist ...
Diese Ursachen können nicht die Datei zu kopieren, weil es von einem anderen Prozess verwendet wird zu sein angehoben. ; (
Hilfe?
class Program
{
static void Main(string[] args)
{
string path = @"D:\levan\FolderListenerTest\ListenedFolder";
FileSystemWatcher listener;
listener = new FileSystemWatcher(path);
listener.Created += new FileSystemEventHandler(listener_Created);
listener.EnableRaisingEvents = true;
while (Console.ReadLine() != "exit") ;
}
public static void listener_Created(object sender, FileSystemEventArgs e)
{
Console.WriteLine
(
"File Created:\n"
+ "ChangeType: " + e.ChangeType
+ "\nName: " + e.Name
+ "\nFullPath: " + e.FullPath
);
File.Copy(e.FullPath, @"D:\levan\FolderListenerTest\CopiedFilesFolder\" + e.Name);
Console.Read();
}
}
Antworten:
Es gibt nur eine Problemumgehung für das Problem, mit dem Sie konfrontiert sind.
Überprüfen Sie, ob die Datei-ID in Bearbeitung ist, bevor Sie mit dem Kopieren beginnen. Sie können die folgende Funktion aufrufen, bis Sie den Wert False erhalten.
1. Methode, direkt aus dieser Antwort kopiert :
private 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; }
2. Methode:
const int ERROR_SHARING_VIOLATION = 32; const int ERROR_LOCK_VIOLATION = 33; private bool IsFileLocked(string file) { //check that problem is not in destination file if (File.Exists(file) == true) { FileStream stream = null; try { stream = File.Open(file, FileMode.Open, FileAccess.ReadWrite, FileShare.None); } catch (Exception ex2) { //_log.WriteLog(ex2, "Error in checking whether file is locked " + file); int errorCode = Marshal.GetHRForException(ex2) & ((1 << 16) - 1); if ((ex2 is IOException) && (errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION)) { return true; } } finally { if (stream != null) stream.Close(); } } return false; }
quelle
ERROR_SHARING_VIOLATION
= 32,ERROR_LOCK_VIOLATION
= 33) zu kopierenAus der Dokumentation für
FileSystemWatcher
:Wenn die Kopie fehlschlägt (Ausnahme abfangen), fügen Sie sie einer Liste von Dateien hinzu, die noch verschoben werden müssen, und versuchen Sie die Kopie während des
OnChanged
Ereignisses. Schließlich sollte es funktionieren.So etwas wie (unvollständig; bestimmte Ausnahmen abfangen, Variablen initialisieren usw.):
public static void listener_Created(object sender, FileSystemEventArgs e) { Console.WriteLine ( "File Created:\n" + "ChangeType: " + e.ChangeType + "\nName: " + e.Name + "\nFullPath: " + e.FullPath ); try { File.Copy(e.FullPath, @"D:\levani\FolderListenerTest\CopiedFilesFolder\" + e.Name); } catch { _waitingForClose.Add(e.FullPath); } Console.Read(); } public static void listener_Changed(object sender, FileSystemEventArgs e) { if (_waitingForClose.Contains(e.FullPath)) { try { File.Copy(...); _waitingForClose.Remove(e.FullPath); } catch {} }
}}
quelle
Es ist ein alter Thread, aber ich werde einige Informationen für andere Leute hinzufügen.
Ich habe ein ähnliches Problem mit einem Programm festgestellt, das PDF-Dateien schreibt. Manchmal dauert das Rendern 30 Sekunden. Dies ist derselbe Zeitraum, den meine watcher_FileCreated-Klasse vor dem Kopieren der Datei wartet.
Die Dateien wurden nicht gesperrt.
In diesem Fall habe ich die Größe der PDF-Datei überprüft und dann 2 Sekunden gewartet, bevor ich die neue Größe verglichen habe. Wenn sie ungleich wären, würde der Thread 30 Sekunden lang schlafen und es erneut versuchen.
quelle
Sie haben tatsächlich Glück - das Programm, das die Datei schreibt, sperrt sie, sodass Sie sie nicht öffnen können. Wenn es nicht gesperrt wäre, hätten Sie eine Teildatei kopiert, ohne zu ahnen, dass ein Problem vorliegt.
Wenn Sie nicht auf eine Datei zugreifen können, können Sie davon ausgehen, dass sie noch verwendet wird (noch besser - versuchen Sie, sie im exklusiven Modus zu öffnen, und prüfen Sie, ob sie gerade von einer anderen Person geöffnet wird, anstatt den Fehler von File.Copy zu erraten). Wenn die Datei gesperrt ist, müssen Sie sie zu einem anderen Zeitpunkt kopieren. Wenn es nicht gesperrt ist, können Sie es kopieren (hier besteht ein geringes Potenzial für eine Rennbedingung).
Wann ist das "andere Mal"? Ich erinnere mich nicht, wenn FileSystemWatcher mehrere Ereignisse pro Datei sendet - probieren Sie es aus, es könnte ausreichen, wenn Sie das Ereignis einfach ignorieren und auf ein anderes warten. Wenn nicht, können Sie jederzeit eine Uhrzeit einrichten und die Datei in 5 Sekunden erneut überprüfen.
quelle
Nun, Sie geben die Antwort bereits selbst; Sie müssen warten, bis die Erstellung der Datei abgeschlossen ist. Eine Möglichkeit, dies zu tun, besteht darin, zu überprüfen, ob die Datei noch verwendet wird. Ein Beispiel hierfür finden Sie hier: Gibt es eine Möglichkeit zu überprüfen, ob eine Datei verwendet wird?
Beachten Sie, dass Sie diesen Code ändern müssen, damit er in Ihrer Situation funktioniert. Vielleicht möchten Sie so etwas wie (Pseudocode) haben:
public static void listener_Created() { while CheckFileInUse() wait 1000 milliseconds CopyFile() }
Natürlich sollten Sie sich vor einer Unendlichkeit schützen,
while
nur für den Fall, dass die Eigentümeranwendung die Sperre niemals aufhebt. Es könnte sich auch lohnen, sich die anderen Ereignisse anzusehen, dieFileSystemWatcher
Sie abonnieren können. Möglicherweise gibt es ein Ereignis, mit dem Sie das gesamte Problem umgehen können.quelle
Wenn die Datei binär geschrieben wird (Byte für Byte), erstellen Sie FileStream und höhere Lösungen. Funktioniert nicht. Da die Datei in allen Bytes bereit und fehlerhaft ist, benötigen Sie in dieser Situation eine andere Problemumgehung wie diese: Führen Sie dies aus, wenn die Datei erstellt wurde oder Sie möchten um die Verarbeitung in der Datei zu starten
long fileSize = 0; currentFile = new FileInfo(path); while (fileSize < currentFile.Length)//check size is stable or increased { fileSize = currentFile.Length;//get current size System.Threading.Thread.Sleep(500);//wait a moment for processing copy currentFile.Refresh();//refresh length value } //Now file is ready for any process!
quelle
Nachdem ich einige dieser und ähnliche Fragen schnell durchgesehen hatte, machte ich heute Nachmittag eine lustige Gänsejagd und versuchte, ein Problem mit zwei separaten Programmen zu lösen, wobei eine Datei als Synchronisationsmethode (und auch zum Speichern von Dateien) verwendet wurde. Eine etwas ungewöhnliche Situation, aber sie hat für mich definitiv die Probleme mit dem Ansatz "Überprüfen, ob die Datei gesperrt ist, öffnen Sie sie, wenn dies nicht der Fall ist" hervorgehoben.
Das Problem ist folgendes: Die Datei kann zwischen dem Zeitpunkt, zu dem Sie sie überprüfen, und dem Zeitpunkt, zu dem Sie die Datei tatsächlich öffnen , gesperrt werden. Es ist wirklich schwierig, das Sporadische aufzuspüren. Die Datei kann nicht kopiert werden, da sie von einem anderen Prozessfehler verwendet wird, wenn Sie nicht auch danach suchen.
Die grundlegende Lösung besteht darin, nur zu versuchen, die Datei in einem catch-Block zu öffnen, damit Sie es erneut versuchen können, wenn sie gesperrt ist. Auf diese Weise vergeht zwischen der Prüfung und dem Öffnen keine Zeit, das Betriebssystem führt sie gleichzeitig aus.
Der Code hier verwendet File.Copy, funktioniert jedoch genauso gut mit allen statischen Methoden der File-Klasse: File.Open, File.ReadAllText, File.WriteAllText usw.
/// <param name="timeout">how long to keep trying in milliseconds</param> static void safeCopy(string src, string dst, int timeout) { while (timeout > 0) { try { File.Copy(src, dst); //don't forget to either return from the function or break out fo the while loop break; } catch (IOException) { //you could do the sleep in here, but its probably a good idea to exit the error handler as soon as possible } Thread.Sleep(100); //if its a very long wait this will acumulate very small errors. //For most things it's probably fine, but if you need precision over a long time span, consider // using some sort of timer or DateTime.Now as a better alternative timeout -= 100; } }
Noch ein kleiner Hinweis zum Parellelismus: Dies ist eine synchrone Methode, die ihren Thread sowohl während des Wartens als auch während der Arbeit am Thread blockiert. Dies ist der einfachste Ansatz. Wenn die Datei jedoch längere Zeit gesperrt bleibt, reagiert Ihr Programm möglicherweise nicht mehr. Parellelismus ist ein zu großes Thema, um hier näher darauf einzugehen (und die Anzahl der Möglichkeiten, wie Sie asynchrones Lesen / Schreiben einrichten können, ist absurd), aber hier ist eine Möglichkeit, wie man es parellelisieren kann.
public class FileEx { public static async void CopyWaitAsync(string src, string dst, int timeout, Action doWhenDone) { while (timeout > 0) { try { File.Copy(src, dst); doWhenDone(); break; } catch (IOException) { } await Task.Delay(100); timeout -= 100; } } public static async Task<string> ReadAllTextWaitAsync(string filePath, int timeout) { while (timeout > 0) { try { return File.ReadAllText(filePath); } catch (IOException) { } await Task.Delay(100); timeout -= 100; } return ""; } public static async void WriteAllTextWaitAsync(string filePath, string contents, int timeout) { while (timeout > 0) { try { File.WriteAllText(filePath, contents); return; } catch (IOException) { } await Task.Delay(100); timeout -= 100; } } }
Und so könnte es verwendet werden:
public static void Main() { test_FileEx(); Console.WriteLine("Me First!"); } public static async void test_FileEx() { await Task.Delay(1); //you can do this, but it gives a compiler warning because it can potentially return immediately without finishing the copy //As a side note, if the file is not locked this will not return until the copy operation completes. Async functions run synchronously //until the first 'await'. See the documentation for async: https://msdn.microsoft.com/en-us/library/hh156513.aspx CopyWaitAsync("file1.txt", "file1.bat", 1000); //this is the normal way of using this kind of async function. Execution of the following lines will always occur AFTER the copy finishes await CopyWaitAsync("file1.txt", "file1.readme", 1000); Console.WriteLine("file1.txt copied to file1.readme"); //The following line doesn't cause a compiler error, but it doesn't make any sense either. ReadAllTextWaitAsync("file1.readme", 1000); //To get the return value of the function, you have to use this function with the await keyword string text = await ReadAllTextWaitAsync("file1.readme", 1000); Console.WriteLine("file1.readme says: " + text); } //Output: //Me First! //file1.txt copied to file1.readme //file1.readme says: Text to be duplicated!
quelle
Mit dem folgenden Code können Sie überprüfen, ob die Datei mit exklusivem Zugriff geöffnet werden kann (dh, sie wird nicht von einer anderen Anwendung geöffnet). Wenn die Datei nicht geschlossen ist, können Sie einige Momente warten und erneut prüfen, bis die Datei geschlossen ist und Sie sie sicher kopieren können.
Sie sollten weiterhin prüfen, ob File.Copy fehlschlägt, da eine andere Anwendung die Datei möglicherweise zwischen dem Zeitpunkt des Überprüfens der Datei und dem Zeitpunkt des Kopierens öffnet.
public static bool IsFileClosed(string filename) { try { using (var inputStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None)) { return true; } } catch (IOException) { return false; } }
quelle
Ich möchte hier eine Antwort hinzufügen, da dies für mich funktioniert hat. Ich benutzte Zeitverzögerungen, während Schleifen, alles, was mir einfiel.
Ich hatte das Windows Explorer-Fenster des Ausgabeordners geöffnet. Ich schloss es und alles funktionierte wie ein Zauber.
Ich hoffe das hilft jemandem.
quelle