У меня есть некоторый код, и когда он выполняется, он бросает IOException
, говоря, что
Процесс не может получить доступ к файлу «имя файла», потому что он используется другим процессом
Что это значит, и что я могу с этим поделать?
c#
.net
language-agnostic
ioexception
Адриано Репетти
источник
источник
Ответы:
В чем причина?
Сообщение об ошибке довольно ясно: вы пытаетесь получить доступ к файлу, и он недоступен, потому что другой процесс (или даже тот же самый процесс) что-то делает с ним (и он не разрешил какой-либо обмен).
Отладка
Это может быть довольно легко решить (или довольно сложно понять), в зависимости от вашего конкретного сценария. Давайте посмотрим некоторые.
Ваш процесс является единственным для доступа к этому файлу.
Вы уверены, что другой процесс - ваш собственный процесс. Если вы знаете, что открываете этот файл в другой части вашей программы, то прежде всего вы должны проверить, правильно ли вы закрываете дескриптор файла после каждого использования. Вот пример кода с этой ошибкой:
К счастью,
FileStream
реализуетIDisposable
, поэтому легко обернуть весь ваш код вusing
оператор:Этот шаблон также гарантирует, что файл не останется открытым в случае исключений (это может быть причиной того, что файл используется: что-то пошло не так, и никто не закрыл его; см. Этот пост для примера).
Если все выглядит нормально (вы уверены, что всегда закрываете каждый файл, который открываете, даже в случае исключений) и у вас есть несколько рабочих потоков, тогда у вас есть два варианта: переработать код для сериализации доступа к файлу (не всегда выполнимо и не всегда хотел) или применить шаблон повторов . Это довольно распространенный шаблон для операций ввода-вывода: вы пытаетесь что-то сделать, а в случае ошибки вы ждете и пытаетесь снова (вы спрашивали себя, например, почему Windows Shell требуется некоторое время, чтобы сообщить вам, что файл используется и нельзя удалить?). В C # это довольно просто реализовать (см. Также лучшие примеры дискового ввода-вывода , работы в сети и доступа к базе данных ).
Обратите внимание на распространенную ошибку, которую мы очень часто видим в StackOverflow:
В этом случае
ReadAllText()
произойдет сбой, потому что файл используется (File.Open()
в строке ранее). Открывать файл заранее не только не нужно, но и неправильно. То же самое относится и ко всемFile
функциям , которые не возвращают дескриптор к файлу вы работаете:File.ReadAllText()
,File.WriteAllText()
,File.ReadAllLines()
,File.WriteAllLines()
и другие (например ,File.AppendAllXyz()
функции) будут все открывать и закрывать файл самостоятельно.Ваш процесс не единственный, кто получает доступ к этому файлу.
Если ваш процесс не единственный, кто получает доступ к этому файлу, взаимодействие может быть более сложным. Шаблон повторных попыток поможет (если файл не должен быть открыт кем - либо еще , но это, то вам необходимо утилита , как Process Explorer , чтобы проверить , кто делает то , что ).
Способов избежать
При необходимости всегда используйте операторы для открытия файлов. Как было сказано в предыдущем абзаце, это поможет вам избежать многих распространенных ошибок (см. Этот пост, где показано, как его не использовать ).
Если возможно, попытайтесь решить, кому принадлежит доступ к определенному файлу, и централизовать доступ несколькими известными способами. Если, например, у вас есть файл данных, в котором ваша программа читает и пишет, вы должны поместить весь код ввода / вывода в один класс. Это облегчит отладку (потому что вы всегда можете поставить точку останова и посмотреть, кто что делает), а также будет точкой синхронизации (если требуется) для множественного доступа.
Не забывайте, что операции ввода-вывода всегда могут быть неудачными, общий пример:
Если кто-то удалит файл после,
File.Exists()
но до этогоFile.Delete()
, он будет помещенIOException
в место, где вы можете ошибочно чувствовать себя в безопасности.Когда это возможно, примените шаблон повтора и, если вы используете
FileSystemWatcher
, рассмотрите возможность отложить действие (потому что вы получите уведомление, но приложение все еще может работать исключительно с этим файлом).Расширенные сценарии
Это не всегда так просто, поэтому вам может потребоваться поделиться доступом с кем-то еще. Если, например, вы читаете от начала и пишете до конца, у вас есть как минимум два варианта.
1) делить то же самое
FileStream
с правильными функциями синхронизации (потому что это не потокобезопасно ). Смотрите этот и этот пост для примера.2) использовать
FileShare
перечисление, чтобы указать ОС разрешить другим процессам (или другим частям вашего собственного процесса) одновременно обращаться к одному и тому же файлу.В этом примере я показал, как открыть файл для записи и поделиться для чтения; обратите внимание, что при чтении и записи перекрытий это приводит к неопределенным или недействительным данным. Это ситуация, которая должна быть обработана при чтении. Также обратите внимание, что это не делает доступ к
stream
потокобезопасным, поэтому этот объект не может быть совместно использован несколькими потоками, если доступ не синхронизирован каким-либо образом (см. Предыдущие ссылки). Другие варианты обмена доступны, и они открывают более сложные сценарии. Пожалуйста, обратитесь к MSDN для более подробной информации.В общем случае N процессов могут читать из одного и того же файла все вместе, но писать должен только один, в контролируемом сценарии вы можете даже разрешить одновременные записи, но это не может быть обобщено в нескольких текстовых параграфах внутри этого ответа.
Можно ли разблокировать файл, используемый другим процессом? Это не всегда безопасно и не так просто, но да, это возможно .
источник
File.Create(path)
, вы должны добавить.Close()
в конце этого, прежде чем писать в него. Подобные подводные камни, помимоusing
операторов для записи файлов, а затем удаления после них. Вы должны опубликовать код в своем вопросе о том, как вы создаете и удаляете свой файл. Но, вероятно, соответствует тому, что упомянуто выше.Directory.SetCreationTimeUTC()
но он не работает, когда File Explorer открыт, утверждая, что к каталогу обращается другой процесс. Как мне справиться с этой ситуацией?Использование FileShare исправило мою проблему открытия файла, даже если он был открыт другим процессом.
источник
Возникла проблема при загрузке изображения, и он не мог удалить его и нашел решение. гл хф
источник
Я получил эту ошибку, потому что я делал File.Move к пути к файлу без имени файла, необходимо указать полный путь в месте назначения.
источник
Ошибка указывает, что другой процесс пытается получить доступ к файлу. Может быть, вы или кто-то еще открыли его, когда вы пытаетесь писать в него. «Чтение» или «Копирование» обычно не вызывают этого, но запись в него или вызов удаления его приведет к этому.
Есть несколько основных вещей, чтобы избежать этого, как уже упоминалось в других ответах:
В
FileStream
операциях поместите его вusing
блок сFileShare.ReadWrite
режимом доступа.Например:
Обратите внимание, что
FileAccess.ReadWrite
это невозможно, если вы используетеFileMode.Append
.Я столкнулся с этой проблемой, когда я использовал поток ввода, чтобы сделать,
File.SaveAs
когда файл использовался. В моем случае я обнаружил, что мне вообще не нужно было сохранять его обратно в файловую систему, поэтому я просто удалил его, но, возможно, я мог бы попытаться создать FileStream вusing
выраженииFileAccess.ReadWrite
, очень похожем на код выше.Сохраните ваши данные в другом файле и вернитесь, чтобы удалить старый файл, если он больше не используется, а затем переименовать тот, который был успешно сохранен, в имя исходного файла. Как вы проверяете файл, который используется, осуществляется с помощью
строка в моем коде ниже, и может быть сделано в службе Windows, в цикле, если у вас есть определенный файл, который вы хотите регулярно просматривать и удалять, когда вы хотите заменить его. Если у вас не всегда один и тот же файл, можно обновить текстовый файл или таблицу базы данных, чтобы служба всегда проверяла имена файлов, а затем выполняла эту проверку для процессов и впоследствии выполняла уничтожение и удаление процессов, как я описываю в следующем варианте. Обратите внимание, что вам понадобится имя пользователя и пароль учетной записи, которые имеют права администратора на данном компьютере, конечно, для выполнения удаления и завершения процессов.
Если вы не знаете, будет ли файл использоваться при попытке сохранить его, вы можете закрыть все процессы, которые могут его использовать, например, Word, если это документ Word, до сохранения.
Если это локально, вы можете сделать это:
Если он удаленный, вы можете сделать это:
где
txtUserName
находится в формеDOMAIN\user
.Допустим, вы не знаете имя процесса, который блокирует файл. Затем вы можете сделать это:
Обратите внимание, что это
file
должен быть путь UNC:\\computer\share\yourdoc.docx
для того,Process
чтобы выяснить, на каком компьютере он находится, иp.MachineName
быть действительным.Ниже приведен класс, используемый этими функциями, который требует добавления ссылки
System.Management
. Код был изначально написан Эриком Дж . :источник
Как указывалось в других ответах в этой теме, для устранения этой ошибки вам необходимо тщательно проверить код, чтобы понять, где файл блокируется.
В моем случае я отправлял файл в виде вложения электронной почты перед выполнением операции перемещения.
Таким образом, файл был заблокирован на пару секунд, пока SMTP-клиент не завершил отправку электронного письма.
Я принял решение сначала переместить файл, а затем отправить электронное письмо. Это решило проблему для меня.
Другое возможное решение, как указывалось ранее Хадсоном, заключалось бы в утилизации объекта после использования.
источник
File.Move()
он не будет работать и выдает ту же ошибку. Если я просто добавляю файл в электронное письмо, я не думаю, что он будет ошибочным при использовании во времяAttachments.Add()
операции, потому что это всего лишь операция копирования. Если это произошло по какой-либо причине, вы можете скопировать его в каталог Temp, прикрепить копию и впоследствии удалить скопированный файл. Но я не думаю, что если ОП захочет изменить файл и использовать его, то этот вид решения (код которого вы не показали, только часть приложения) сработал бы..Dispose()
это всегда хорошая идея, но здесь она не актуальна, если файл не открыт в предыдущей операции.У меня был следующий сценарий, который вызывал ту же ошибку:
Большинство файлы были небольшими по размеру, однако, некоторые из них были большими, и поэтому попытка удалить те привели к нет доступа к файлу ошибки.
Было нелегко найти решение, однако, решение было таким же простым, как ожидание «завершения задачи»:
источник
Приведенный ниже код решает эту проблему, но я предлагаю Прежде всего вам нужно понять, что является причиной этой проблемы, и попробовать решение, которое вы можете найти, изменив код
Я могу дать другой способ решения этой проблемы, но лучшее решение - проверить структуру вашего кода и попытаться проанализировать, что делает это, если вы не нашли никакого решения, вы можете воспользоваться этим кодом ниже.
источник
GC.*()
, возможно, у вас другие проблемы с вашим кодом. 2) Сообщение локализовано и хрупко , вместо этого используйте HRESULT. 3) Вы можете спать сTask.Delay()
(и десять секунд во многих случаях как-то чрезмерно). 4) У вас нет условия выхода: этот код может зависнуть навсегда. 5) Тебе здесь точно не нужноgoto
. 6) Поймать,Exception
как правило, плохая идея, в данном случае также потому, что ... 6) Если что-то случится, вы глотаете ошибку.GC.Collect()
, был при работе с некоторыми объектами COM.