Как проверить, полностью ли скопирован файл в .NET.
Я отслеживаю папку для новых файлов и должен их обрабатывать. Проблема в том, что иногда открытие файла не выполняется, потому что система не закончила его копирование.
Каков правильный способ проверить, завершено ли копирование файла?
Разъяснение:
У меня нет прав на запись в папку/файлы и невозможно управлять процессом копирования (это пользователь).
Ответы
Ответ 1
Я думаю, что единственный верный способ сделать это - попытаться открыть файл исключительно и поймать конкретное исключение. Я обычно ненавижу использовать исключения для обычной логики приложения, но я боюсь, что для этого сценария нет другого пути (по крайней мере, я еще не нашел его):
public bool FileIsDone(string path)
{
try
{
using (File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None))
{
}
}
catch(UnauthorizedAccessException)
{
return false;
}
return true;
}
Ответ 2
Не уверен относительно "правильного пути", но вы можете использовать инструмент мониторинга (FileSystemWatcher
, я думаю), чтобы заполнить внутреннюю очередь, которую вы используете для отложенной обработки. Или еще лучше: просто используйте очередь для размещения файлов, в которых был открытый сбой, поэтому вы можете повторить их позже.
Ответ 3
Если вы используете FileSystemWatcher, я не думаю, что там есть надежное решение этой проблемы. Один из подходов - попытка/уловка/повторная попытка позже.
Ответ 4
один подход, который я всегда делаю, - это создать файл в конце моей копии/передачи с именем "token.txt" без содержимого. Идея состоит в том, что этот файл будет создан только в конце операции передачи, поэтому вы можете отслеживать создание этого файла, и когда этот файл будет создан, вы начнете работать с вашими файлами. Не забывайте стирать этот файл токена всегда, когда вы начинаете обрабатывать ваши файлы.
Ответ 5
Вы также должны учитывать такие случаи, как: файл используется другой программой, файл был удален (копия не удалась) и т.д.
Используйте расширенную обработку исключений, чтобы охватить все важные случаи, которые могут возникнуть.
Ответ 6
Это зависит от того, что цикл повтора, вероятно, лучше всего подходит, если у вас нет контроля над процессом копирования.
Если у вас есть контроль:
- Если папка локальная, вы можете потребовать, чтобы люди, записывающие в нее файлы, блокировали файл для эксклюзивного доступа и освобождали блокировку только после их завершения (что, по-моему, по умолчанию для File.Copy). На стороне .Net у вас может быть простой цикл повтора с периодом охлаждения.
- В качестве альтернативы вы можете записать файл в временную папку и только после того, как его переместите в целевой каталог. Это уменьшает окно, в котором могут произойти плохие вещи (но не устраняет их).
- Если папка является общим ресурсом SMB, есть шанс LockFile даже не работать (некоторые реализации Linux). В этом случае общий подход заключается в том, чтобы иметь файл блокировки, который удаляется после того, как человек, создающий файл, будет выполнен. Проблема с файлом блокировки заключается в том, что если вы забудете удалить его, у вас могут быть проблемы.
- Вследствие этих осложнений я бы рекомендовал, чтобы получение данных через службу WCF или веб-службу могло быть выгодным, потому что у вас есть намного лучший контроль.
Ответ 7
Фактически, чтобы избежать условий гонки, единственное безопасное решение - повторить попытку.
Если вы сделаете что-то вроде:
while (file is locked)
no-op()
process file()
Вы рискуете другим процессом, прыгающим между защитой while и инструкцией файла процесса. Независимо от того, как выполняется ваше "ожидание доступности файлов", если вы не можете гарантировать, что после разблокировки вы первый процесс доступа к нему, возможно, вы не первый пользователь.
Это более вероятно, что может показаться на первый взгляд, особенно если несколько человек смотрят файл, и, в частности, если они используют что-то вроде наблюдателя файловой системы. Конечно, это еще не особенно вероятно даже тогда...
Ответ 8
Большие ли файлы?
Возможно, вы могли бы попытаться вычислить контрольную сумму md5 в файле?
Если вы помещаете хэш файл md5 в имя файла, вы можете его восстановить и попытаться пересчитать контрольную сумму в файле. Когда md5 является совпадением, вы можете предположить, что файл завершен.
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"));
Ответ 9
Здесь используется цикл vb.net.
Он ждет 2 секунды между каждой проверкой.
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