Отже, швидко оглянувши деякі з цих та інших подібних питань, сьогодні вдень я вирушив у веселу погоню за гусями, намагаючись вирішити проблему з двома окремими програмами, використовуючи файл як метод синхронізації (а також збереження файлів). Трохи незвична ситуація, але вона, безумовно, висвітлила для мене проблеми з підходом "перевірити, чи файл заблоковано, а потім відкрити його, якщо ні".
Проблема полягає в наступному: файл може стати замкнений між часом , що ви перевірити його і час , яке ви на самому справі відкрити файл. Дійсно важко відстежити спорадичні Не вдається скопіювати файл, оскільки він використовується іншим процесом помилкою якщо ви його теж не шукаєте.
Основна роздільна здатність - просто спробувати відкрити файл всередині блоку catch, щоб, якщо його заблоковано, ви могли спробувати ще раз. Таким чином, немає часу, що минув між перевіркою та відкриттям, ОС робить їх одночасно.
Тут використовується код File.Copy, але він працює так само добре з будь-яким із статичних методів класу File: File.Open, File.ReadAllText, File.WriteAllText тощо.
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;
}
}
Ще одна невеличка примітка щодо парелелізму:
Це синхронний метод, який блокує його потік як під час очікування, так і під час роботи над потоком. Це найпростіший підхід, але якщо файл тривалий час залишається заблокованим, програма може не реагувати. Парелелізм - це занадто велика тема, щоб його можна було глибше заглибитись (і кількість способів, якими ви можете налаштувати асинхронне читання / запис, є якось недоречною), але тут є один із способів його усунення.
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;
}
}
}
І ось як його можна використовувати:
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);
}