Как проверить, полностью ли скопирован файл in.NET

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

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

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

9 ответов


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

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

  return true;
}

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


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


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


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

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


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

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

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

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

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

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

вы рискуете другим процессом, прыгающим между while guard и инструкцией файла процесса. Независимо от того, как реализовано ваше" ожидание доступности файла", если вы не можете гарантировать, что после разблокировки вы первый процесс доступа к нему, вы можете не быть первым пользователем.

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


большие файлы?

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

вот 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