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.
static void safeCopy(string src, string dst, int timeout)
{
while (timeout > 0)
{
try
{
File.Copy(src, dst);
break;
}
catch (IOException)
{
}
Thread.Sleep(100);
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);
CopyWaitAsync("file1.txt", "file1.bat", 1000);
await CopyWaitAsync("file1.txt", "file1.readme", 1000);
Console.WriteLine("file1.txt copied to file1.readme");
ReadAllTextWaitAsync("file1.readme", 1000);
string text = await ReadAllTextWaitAsync("file1.readme", 1000);
Console.WriteLine("file1.readme says: " + text);
}