Подождите, пока файл не будет полностью записан

Когда файл создается ( FileSystemWatcher_Created ) в одном каталоге, я копирую его в другой. Но когда я создаю большой (> 10 МБ) файл, он не может скопировать файл, потому что он уже начинает копирование, когда создание файла еще не завершено …
Это вызывает Невозможно скопировать файл, потому что он используется другим процессом для поднятия. ; (
Есть помощь?

  class Program {static void Main (string [] args) {string path = @ "D:  levan  FolderListenerTest  ListenedFolder  "; FileSystemWatcher listener; listener = new FileSystemWatcher (path); listener.Created + = new FileSystemEventHandler (listener_Created); listener.EnableRaisingEvents = true; while (Console.ReadLine ()! =" Exit ");} public static void listener_Created (  отправитель объекта, FileSystemEventArgs e) {Console.WriteLine ("Файл создан:  n" + "ChangeType:" + e.ChangeType + " nName:" + e.Name + " nFullPath:" + e.FullPath); Файл  .Copy (e.FullPath, @ "D:  levan  FolderListenerTest  CopiedFilesFolder " + e.Name); Console.Read ();}}  

Существует только обходной путь для проблемы, с которой вы столкнулись.

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

1-й метод, скопированный непосредственно из этого ответа:

  private bool IsFileLocke  d (файл FileInfo) {поток FileStream = null;  попробуйте {stream = file.Open (FileMode.Open, FileAccess.ReadWrite, FileShare.None);  } catch (IOException) {//файл недоступен, потому что он://все еще записывается в//или обрабатывается другим потоком//или не существует (уже был обработан) return true;  } наконец {если (поток! = null) stream.Close ();  }//файл не заблокирован return false;}  

2-й способ:

   const int ERROR_SHARING_VIOLATION = 32; const int ERROR_LOCK_VIOLATION = 33; private bool IsFileLocked (строковый файл) {//проверяем, что проблема не в конечном файле if (File.Exists (file) == true) {FileStream stream = null;  попробуйте {stream = File.Open (файл, FileMode.Open, FileAccess.ReadWrite, FileShare.None);  } catch (Exception ex2) {//_log.WriteLog(ex2, «Ошибка проверки, заблокирован ли файл» + файл);  int errorCode = Marshal.GetHRForException (ex2) & ((1  

15

Из документации для FileSystemWatcher :

Событие OnCreated возникает, как только файл создан. Если файл копируется или переносится в отслеживаемый каталог, немедленно вызывается событие OnCreated , за которым следует одно или несколько событий OnChanged .

Итак, если копирование не удается (перехватить исключение), добавьте его в список файлов, которые все еще нужно переместить, и попытайтесь скопировать во время OnChanged код> событие. В конце концов, это должно сработать.

Что-то вроде (неполное; перехват определенных исключений, инициализация переменных и т. Д.):

  public static void listener_Created (object  отправитель, FileSystemEventArgs e) {Console.WriteLine ("Файл создан:  n" + "ChangeType:" + e.ChangeType + " nName:" + e.Name + " nFullPath:" + e.FullPath);  попробуйте {File.Copy (e.FullPath, @ "D:  levani  FolderListenerTest  CopiedFilesFolder " + e.Name);  } catch {_waitingForClose.Add (e.FullPath);  } Console.Read ();} public static void listener_Changed (объект-отправитель, FileSystemEventArgs e) {if (_waitingForClose.Contains (e.FullPath)) {попробуйте {File.Copy (...);  _waitingForClose.Remove (e.FullPath);  } catch {}}  

}

Поделиться
Улучшить этот ответ
отредактировано 12 августа ’20 в 07:17
AustinWBryan
2,90133 золотых знака1616 серебряных знаков3535 бронзовых знаков
ответ дан 11 июня ’12 в 17: 36
  • это неплохой способ, но он мне нужен сразу, поэтому я положил IsFileReady на время, и теперь он работает — Леви 11 июня 2012, 14:50
добавить комментарий |

Из документации для FileSystemWatcher :

Событие OnCreated возникает, как только файл создается. Если файл копируется или переносится в отслеживаемый каталог, немедленно вызывается событие OnCreated , за которым следует одно или несколько событий OnChanged .

Итак, если копирование не удается (перехватить исключение), добавьте его в список файлов, которые все еще нужно переместить, и попытайтесь скопировать во время OnChanged код> событие. В конце концов, это должно сработать.

Что-то вроде (неполное; перехват определенных исключений, инициализация переменных и т. Д.):

  public static void listener_Created (object  отправитель, FileSystemEventArgs e) {Console.WriteLine ("Файл создан:  n" + "ChangeType:" + e.ChangeType + " nName:" + e.Name + " nFullPath:" + e.FullPath);  попробуйте {File.Copy (e.FullPath, @ "D:  levani  FolderListenerTest  CopiedFilesFolder " + e.Name);  } catch {_waitingForClose.Add (e.FullPath);  } Приставка. Read ();} public static void listener_Changed (объект-отправитель, FileSystemEventArgs e) {if (_waitingForClose.Contains (e.FullPath)) {try {File.Copy (...);  _waitingForClose.Remove (e.FullPath);  } catch {}}  

}


11

Это старый поток, но я добавлю некоторую информацию для других.

У меня возникла аналогичная проблема с программой, которая записывает файлы PDF, иногда им требуется 30 секунд для рендеринга … это тот же период, который мой класс watcher_FileCreated ожидает перед копированием файла.

Файлы не были заблокированы.

В этом случае Я проверил размер PDF-файла, а затем подождал 2 секунды, прежде чем сравнивать новый размер, если бы они были неравными, поток перестал бы спать на 30 секунд и попытался бы снова.

Поделиться
Улучшить этот ответ
ответил 20 мая ’15 в 2:24
добавить комментарий т |

Это старая ветка, но я добавлю некоторую информацию для других.

Я испытал аналогичная проблема с программой, которая записывает файлы PDF, иногда им требуется 30 секунд для рендеринга … это тот же период, который мой класс watcher_FileCreated ждет перед копированием файла.

Файлы не были заблокированы.

В этом случае я проверил размер PDF-файла, а затем подождал 2 секунды, прежде чем сравнивать новый размер, если бы они были неравными, поток засыпал бы на 30 секунд и повторил попытку.


5

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

Если вы не можете получить доступ к файлу, вы можете предположить, что он все еще используется ( еще лучше — попробуйте открыть его в монопольном режиме и посмотрите, открывает ли его кто-то еще, вместо того, чтобы гадать на основании сбоя File.Copy). Если файл заблокирован, вам придется скопировать его в другой раз. Если он не заблокирован, вы можете скопировать его (здесь есть небольшая вероятность состояния гонки).

Когда это «в другой раз»? Я не помню, когда FileSystemWatcher отправляет несколько событий для каждого файла — проверьте это, вам может быть достаточно просто проигнорировать событие и дождаться другого. Если нет, вы всегда можете установить время и перепроверить файл через 5 секунд..

Поделиться
Улучшите это ответ
Создан 11 июня 2012, 17:35.
добавить комментарий |

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

Если вы не можете получить доступ к файлу, вы можете предположить, что он все еще используется ( еще лучше — попробуйте открыть его в монопольном режиме и посмотрите, открывает ли его кто-то еще, вместо того, чтобы гадать на основании сбоя File.Copy). Если файл заблокирован, вам придется скопировать его в другой раз. Если он не заблокирован, вы можете скопировать его (здесь есть небольшая вероятность состояния гонки).

Когда это «в другой раз»? Я не помню, когда FileSystemWatcher отправляет несколько событий для каждого файла — проверьте это, вам может быть достаточно просто проигнорировать событие и дождаться другого. В противном случае вы всегда можете установить время и перепроверить файл через 5 секунд.


3

Ну, вы уже сами ответили; вам нужно дождаться завершения создания файла. Один из способов сделать это — проверить, используется ли еще файл. Пример этого можно найти здесь: Есть ли способ проверить, используется ли файл?

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

  public static void listener_Created () {while CheckFileInUse () wait 1000 миллисекунд CopyFile ()}  

Очевидно, вам следует защитить себя от бесконечного while на тот случай, если приложение-владелец никогда не снимает блокировку. Кроме того, возможно, стоит проверить другие события из FileSystemWatcher , на которые вы можете подписаться. Возможно, существует событие, которое вы можете использовать, чтобы обойти эту проблему.

Поделиться
Улучшить этот ответ
отредактировано 23 мая ’17 в 12:18
Сообщество ♦
111 серебряный значок
ответил 11 июня ’12 в 14: 37
добавить комментарий |

Ну, вы уже сами ответили; вам нужно дождаться завершения создания файла. Один из способов сделать это — проверить, используется ли еще файл.. Пример этого можно найти здесь: Есть ли способ проверить, используется ли файл?

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

  public static void listener_Created () {while CheckFileInUse () wait 1000 миллисекунд CopyFile ()}  

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


2

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

  long fileSize = 0; currentFile = new FileInfo (path); while (fileSize  

Поделиться
Улучшить этот ответ
ответил 15 ноя 2016, 13:24
добавить комментарий |

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

  long fileSize = 0; currentFile = new FileInfo  (путь); while (fileSize  

2

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

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

Основная Решение — просто попытаться открыть файл внутри блока catch, чтобы, если он заблокирован, вы могли попробовать еще раз. Таким образом, между проверкой и открытием не будет промежутка времени, операционная система сделает их одновременно.

Код здесь использует File.Copy, но он также хорошо работает с любым из статических методов класса File: File.Open, File.ReadAllText, File.WriteAllText и т. д.

 /// как долго продолжать попытки в миллисекундах  static void safeCopy (string src, string dst, int timeout) {while (  тайм-аут> 0) {попробуйте {File.Copy (src, dst); //не забудьте либо вернуться из функции, либо прервать цикл while break;  } catch (IOException) {//здесь можно спать, но, вероятно, лучше как можно скорее выйти из обработчика ошибок} Thread.Sleep (100); //если ждать очень долго, будут накапливаться очень маленькие ошибки. //Для большинства вещей это, вероятно, нормально, но если вам нужна точность в течение длительного периода времени, рассмотрите//использование какого-то таймера или DateTime.Now в качестве лучшей альтернативы timeout - = 100;  }}  

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

  открытый класс FileEx {public static async void CopyWaitAsync (string src, string dst, int timeout, Action doWhenDone) {while (timeout> 0) {try {File.Copy (src, dst);  doWhenDone ();  сломать;  } catch (IOException) {} ожидание Task.Delay (100);  таймаут - = 100;  }} общедоступная статическая асинхронная задача  ReadAllTextWaitAsync (string filePath, int timeout) {while (timeout> 0) {try {return File.ReadAllText (filePath);  } catch (IOException) {} ожидание Task.Delay (100);  таймаут - = 100;  } возвращение "";  } public static async void WriteAllTextWaitAsync (string filePath, string contents, int timeout) {while (timeout> 0) {try {File.WriteAllText (filePath, contents);  возвращение;  } catch (IOException) {} ожидание Task.Delay (100);  таймаут - = 100;  }}}  

И вот как это можно использовать:

  public static void Main () {test_FileEx ();  Приставка. WriteLine («Я первый!»);} Public static async void test_FileEx () {await Task.Delay (1); //вы можете это сделать, но это дает предупреждение компилятору, потому что он потенциально может немедленно вернуться, не завершив копирование//В качестве дополнительного примечания, если файл не заблокирован, он не вернется, пока операция копирования не завершится.  Асинхронные функции выполняются//синхронно до первого "ожидания".  См. Документацию по async: https://msdn.microsoft.com/en-us/library/hh156513.aspx CopyWaitAsync ("file1.txt", "file1.bat", 1000); //это нормальный способ использования такой асинхронной функции.  Выполнение следующих строк всегда будет происходить ПОСЛЕ завершения копирования await CopyWaitAsync ("file1.txt", "file1.readme", 1000);  Console.WriteLine ("file1.txt скопирован в file1.readme"); //Следующая строка не вызывает ошибки компилятора, но и не имеет смысла.  ReadAllTextWaitAsync ("file1.readme", 1000); //Чтобы получить возвращаемое значение функции, вы должны использовать эту функцию с ключевым словом await string text = await ReadAllTextWaitAsync ("file1.readme", 1000);  Console.WriteLine ("file1.readme говорит:" + text);}//Вывод://Сначала я!//file1.txt скопирован в file1.readme//file1.readme говорит: Текст для дублирования!  

Поделиться
Улучшить этот ответ
ответил 06 янв. в 2:26
добавить комментарий |

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

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

Основная Решение — просто попытаться открыть файл внутри блока catch, чтобы, если он заблокирован, вы могли попробовать еще раз. Таким образом, между проверкой и открытием не будет промежутка времени, операционная система сделает их одновременно.

В этом коде используется File.Copy, но он также хорошо работает с любым из статических методов класса File: File.Open, File.ReadAllText, File.WriteAllText и т. д..

 /// как долго продолжать попытки в миллисекундах  static void safeCopy (string src, string dst, int timeout) {  while (тайм-аут> 0) {попробуйте {File.Copy (src, dst); //не забудьте либо вернуться из функции, либо прервать цикл while break;  } catch (IOException) {//здесь можно спать, но, вероятно, лучше как можно скорее выйти из обработчика ошибок} Thread.Sleep (100); //если ждать очень долго, будут накапливаться очень маленькие ошибки. //Для большинства вещей это, вероятно, нормально, но если вам нужна точность в течение длительного периода времени, рассмотрите//использование какого-то таймера или DateTime.Now в качестве лучшей альтернативы timeout - = 100;  }}  

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

  открытый класс FileEx {public static async void CopyWaitAsync (string src, string dst, int timeout, Action doWhenDone) {while (timeout> 0) {try {File.Copy (src, dst);  doWhenDone ();  сломать;  } catch (IOException) {} ожидание Task.Delay (100);  таймаут - = 100;  }} общедоступная статическая асинхронная задача  ReadAllTextWaitAsync (string filePath, int timeout) {while (timeout> 0) {try {return File.ReadAllText (filePath);  } catch (IOException) {} ожидание Task.Delay (100);  таймаут - = 100;  } возвращение "";  } public static async void WriteAllTextWaitAsync (string filePath, string contents, int timeout) {while (timeout> 0) {try {File.WriteAllText (filePath, contents);  возвращение;  } catch (IOException) {} ожидание Task.Delay (100);  таймаут - = 100;  }}}  

И вот как это можно использовать:

  public static void Main () {test_FileEx ();  Console.WriteLine («Я первый!»);} Общедоступный статический асинхронный вызов void test_FileEx () {ожидание Task.Delay (1); //вы можете это сделать, но это дает предупреждение компилятору, потому что он потенциально может немедленно вернуться, не завершив копирование//В качестве дополнительного примечания, если файл не заблокирован, он не вернется, пока операция копирования не завершится.  Асинхронные функции выполняются//синхронно до первого "ожидания".  См. Документацию по async: https://msdn.microsoft.com/en-us/library/hh156513.aspx CopyWaitAsync ("file1.txt", "file1.bat", 1000); //это нормальный способ использования такой асинхронной функции.  Выполнение следующих строк всегда будет происходить ПОСЛЕ завершения копирования await CopyWaitAsync ("file1.txt", "file1.readme", 1000);  Console.WriteLine ("файл1.txt скопирован в файл1. readme ");//Следующая строка не вызывает ошибки компилятора, но и не имеет смысла. ReadAllTextWaitAsync (" file1.readme ", 1000);//Чтобы получить возвращаемое значение функции, вы  необходимо использовать эту функцию с ключевым словом await string text = await ReadAllTextWaitAsync ("file1.readme", 1000); Console.WriteLine ("file1.readme говорит:" + text);}//Вывод://Сначала я!//file1.txt, скопированный в file1.readme//file1.readme говорит: Текст должен быть продублирован!  

0

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

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

  public static bool IsFileClosed (string filename) {try {using (var inputStream = File.Open (filename, FileMode.Open, FileAccess.  Прочтите, FileShare.None)) {return true;  }} catch (IOException) {вернуть ложь;  }}  

Поделиться
Улучшите этот ответ
ответил 11 июня ’12 в 14:43
  • Что возвращает этот код, если вы обнаружите исключение, которое не является исключением IOException? — Уильям Дэниел, 12 янв., 18:49
  • Если File.Open вызывает исключение, отличное от IOException, этот метод не возвращает значение. В обязанности вызывающего абонента входит проверка любых исключений, не связанных с IOExceptions, которые могут возникнуть: msdn.microsoft.com/en-us/library/y973b725(v=vs.110).aspx — Майкл, 13 января 2016, 20:20: 00
добавить комментарий |

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

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

  public static bool IsFileClosed (string filename) {try {using (var inputStream = File  .Open (имя файла, FileMode.Open, FileAccess.Read, FileShare. Нет)) {return true;  }} catch (IOException) {вернуть ложь;  }}  

-5

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

У меня было открыто окно Windows Explorer выходной папки. Я закрыл его, и все заработало как шарм.

Надеюсь, это кому-то поможет.

Поделиться
Улучшить этот ответ
ответил 30 июля ’15 в 12:47
  • 4
    Итак, теперь ваше приложение вылетает, если у пользователя открыт этот каталог? — Epirocks 3 фев 2016, в 9:17
добавить комментарий |

Я хотел бы добавить здесь ответ, потому что это сработало для меня. Я использовал временные задержки, а циклы — все, что я мог придумать.

У меня было открыто окно Windows Explorer выходной папки. Я закрыл его, и все заработало как шарм.

Надеюсь, это кому-то поможет.

Оцените статью
Botgadget.ru
Добавить комментарий