2009-07-20 8 views
12

Я отслеживаю папку для новых файлов и должен обрабатывать их. Проблема в том, что иногда открытие файла не выполняется, потому что система не закончила его копирование.Как проверить, полностью ли скопирован файл в .NET.

Каков правильный способ проверить, закончилось ли копирование файла?

Уточнение: У меня нет прав на запись в папку/файлы и невозможно управлять процессом копирования (это пользователь).

+0

Хороший вопрос! Когда у меня была эта проблема, я просто добавил System.Threading.Thread.Sleep (1000), но я бы * хотел * получить лучшее решение (это так просто ...) – Treb

+0

У вас есть доступ к исходному файлу, который копируется? –

ответ

11

Я думаю, что единственный верный способ сделать это - попытаться открыть файл исключительно и поймать конкретное исключение.Обычно я ненавижу использование исключений для нормальной логики приложения, но я боюсь, что для этого сценария нет другого пути (по крайней мере, я не нашел пока):

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

    return true; 
} 
0

Один подход, который я беру всегда, - это создать файл в конце моей копии/передачи с именем «token.txt» без содержимого. Идея состоит в том, что этот файл будет создан только в конце операции передачи, поэтому вы можете отслеживать создание этого файла, и когда этот файл будет создан, вы начнете работать с вашими файлами. Не забывайте стирать этот файл токена всегда, когда вы начинаете обрабатывать ваши файлы.

+1

Но если учетная запись пользователя не имеет права удалять файлы на сервере, тогда этот подход был бы бесполезен. – rahul

+2

Не думайте, что экстраполяция ждет процесса копирования, который он сам контролирует. Значит, тогда не было бы токена, верно? – peSHIr

+1

Я думаю, вы не можете сказать, имеет ли он или нет доступ/контроль без процесса без каких-либо подробностей. Это похоже на мозговой штурм, где каждый дает исходные данные. –

0

Вы должны также охватывать случаи, такие как: файл используется другой программой, файл был удален (копия не удалось) и т.д ..

Использование расширенной обработки исключений, чтобы охватить все важные случаи, которые могут произойти.

2

Не уверен относительно «правильного пути», но вы можете использовать инструмент мониторинга (FileSystemWatcher, я думаю), чтобы заполнить внутреннюю очередь, которую вы используете для отложенной обработки. Или еще лучше: просто используйте очередь для размещения файлов, у которых был открытый сбой, поэтому вы можете повторить их позже.

1

Если вы используете FileSystemWatcher, я не думаю, что есть надежное решение этой проблемы. Один из подходов - попытка/уловка/повторная попытка позже.

0

Это зависит от того, что цикл повтора, вероятно, лучший, что вы можете сделать, если у вас нет контроля над процессом копирования.

Если у вас есть контроль:

  • Если папка является локальной, вы можете потребовать, чтобы люди пишущих вещей в нем заблокировать файл для монопольного доступа, и только снять блокировку, когда они сделаны (которые Я думаю, что по умолчанию для File.Copy). На стороне .Net у вас может быть простой цикл повтора с периодом охлаждения.
    • В качестве альтернативы вы можете записать файл в временную папку и только после того, как его переместите в целевой каталог. Это уменьшает окно, где плохие вещи могут произойти (но не устраняет ее)
  • Если папка является доля SMB, есть шанс LockFile даже не работает (в некоторых реализациях Linux). В этом случае общий подход заключается в том, чтобы иметь файл блокировки, который удаляется после того, как человек, создающий файл, будет выполнен. Проблема с файлом блокировки заключается в том, что если вы забудете удалить его, у вас могут быть проблемы.
  • Вследствие этих осложнений я бы рекомендовал, чтобы получение данных через службу WCF или веб-службу могло быть выгодным, потому что у вас есть намного лучший контроль.
0

На самом деле, чтобы избежать гонок условия, только безопасное решение - повторить попытку.

Если вы что-то вроде:

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

Вы рискуете другой процесс прыжков между этим временем настороже и утверждением файла процесса. Независимо от того, как будет реализовано ваше «ожидание доступности файлов», если вы не можете гарантировать, что после разблокировки вы первый процесс доступа к нему, вы можете не быть первым пользователем.

Это более вероятно, что может показаться на первый взгляд, в частности, если несколько человек смотрят файл, и, в частности, если они используют что-то вроде наблюдателя файловой системы. Конечно, это еще не особенно вероятно даже тогда ...

0

Являются ли файлы большими?

Возможно, вы могли бы попытаться вычислить контрольную сумму 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")); 
0

Вот цикл 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 
Смежные вопросы