Как проверить, полностью ли скопирован файл в .NET - PullRequest
12 голосов
/ 20 июля 2009

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

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

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

Ответы [ 9 ]

11 голосов
/ 20 июля 2009

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

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

  return true;
}
2 голосов
/ 20 июля 2009

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

1 голос
/ 20 июля 2009

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

0 голосов
/ 13 июля 2017

Вот цикл 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
0 голосов
/ 20 июля 2009

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

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

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

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

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

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

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

0 голосов
/ 20 июля 2009

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

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

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

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

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

0 голосов
/ 20 июля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...