Какой самый простой способ заблокировать поток до тех пор, пока файл не будет разблокирован и доступен для чтения и переименования? Например, есть ли где-нибудь в .NET Framework WaitOnFile ()?
У меня есть служба, которая использует FileSystemWatcher для поиска файлов, которые должны быть переданы на FTP-сайт, но событие создания файла срабатывает до того, как другой процесс завершит запись файла.
Идеальное решение было бы иметь период тайм-аута, чтобы поток не зависал навсегда, прежде чем сдаться.
Изменить: опробовав некоторые из приведенных ниже решений, я изменил систему так, чтобы все файлы записывались Path.GetTempFileName()
, а затем выполняли File.Move()
их в окончательном месте. Как только FileSystemWatcher
событие сработало, файл уже был готов.
Ответы:
Это был ответ, который я дал на связанный с этим вопрос :
источник
Начиная с ответа Эрика, я включил некоторые улучшения, чтобы сделать код более компактным и многоразовым. Надеюсь, это будет полезно.
источник
using
нуля, просто проверьте наличие null внутриusing
блока.fs
быть нулевым вcatch
блоке? ЕслиFileStream
конструктор выбрасывает, переменной не будет присвоено значение, и нет ничего другого внутри,try
что могло бы вызватьIOException
. Мне кажется, что это нормально - просто делатьreturn new FileStream(...)
.Вот общий код для этого, не зависящий от самой операции с файлом. Это пример того, как его использовать:
или
Вы также можете определить количество повторов и время ожидания между повторами.
ПРИМЕЧАНИЕ. К сожалению, основная ошибка Win32 (ERROR_SHARING_VIOLATION) не отображается в .NET, поэтому я добавил небольшую функцию взлома (
IsSharingViolation
), основанную на механизмах отражения, чтобы проверить это.источник
SharingViolationException
. Фактически, они могут быть обратно совместимыми, если они происходят отIOException
. И они действительно должны.Starting with the .NET Framework 4.5, the HResult property's setter is protected, whereas its getter is public. In previous versions of the .NET Framework, both getter and setter are protected.
Я собрал вспомогательный класс для таких вещей. Это сработает, если вы контролируете все, что имеет доступ к файлу. Если вы ожидаете разногласий от множества других вещей, то это бесполезно.
Он работает с использованием именованного мьютекса. Те, кто желает получить доступ к файлу, пытаются получить контроль над именованным мьютексом, который разделяет имя файла (с символами '\' превращенными в '/'). Вы можете либо использовать Open (), который будет останавливаться до тех пор, пока мьютекс не станет доступным, либо вы можете использовать TryOpen (TimeSpan), который пытается получить мьютекс в течение заданного времени и возвращает false, если он не может быть получен в течение указанного промежутка времени. Скорее всего, это следует использовать внутри блока using, чтобы гарантировать, что блокировки снимаются должным образом, и поток (если он открыт) будет правильно удален при удалении этого объекта.
Я провел быстрый тест с ~ 20 объектами для различных операций чтения / записи файла и не обнаружил повреждений. Очевидно, что это не очень продвинутый вариант, но он должен работать в большинстве простых случаев.
источник
Для этого конкретного приложения непосредственное наблюдение за файлом неизбежно приведет к трудно отслеживаемой ошибке, особенно при увеличении размера файла. Вот две разные стратегии, которые будут работать.
Удачи!
источник
Некоторое время назад я использовал один из приемов - написание собственной функции. В основном перехватите исключение и повторите попытку, используя таймер, который вы можете запустить в течение определенного времени. Если есть способ получше, поделитесь пожалуйста.
источник
Из MSDN :
Ваш FileSystemWatcher можно изменить так, чтобы он не выполнял чтение / переименование во время события «OnCreated», а:
источник
В большинстве случаев будет работать простой подход, например, предложенный @harpo. Используя такой подход, вы можете разработать более сложный код:
источник
Объявление для передачи файла триггера процесса SameNameASTrasferFile.trg, который создается после завершения передачи файла.
Затем настройте FileSystemWatcher, который будет запускать событие только для файла * .trg.
источник
Я не знаю, что вы используете для определения статуса блокировки файла, но что-то вроде этого должно это сделать.
источник
Возможным решением было бы объединить наблюдатель файловой системы с некоторым опросом,
получать уведомление для каждого изменения в файле, и при получении уведомления проверьте, заблокирован ли он, как указано в принятом в настоящее время ответе: https://stackoverflow.com/a/50800/6754146 Код для открытия файлового потока копируется из ответа и немного изменено:
Таким образом вы можете проверить файл, если он заблокирован, и получить уведомление, когда он закрыт по указанному обратному вызову, таким образом вы избегаете чрезмерно агрессивного опроса и выполняете работу только тогда, когда он может быть фактически закрыт
источник
Я делаю это так же, как Гульзар, просто продолжаю пробовать петлей.
На самом деле я даже не беспокоюсь о наблюдателе файловой системы. Опрашивать сетевой диск о новых файлах раз в минуту - это дешево.
источник
Просто используйте событие Changed с NotifyFilter NotifyFilters.LastWrite :
источник
Я столкнулся с аналогичной проблемой при добавлении вложения Outlook. «Использование» спасло положение.
источник
Как насчет этого как варианта:
Конечно, если размер файла предварительно выделен при создании, вы получите ложное срабатывание.
источник