IOException: процесс не может получить доступ к файлу "путь к файлу", потому что он используется другим процессом
У меня есть некоторый код, и когда он выполняет, он бросает!--0-->, сказав, что
процесс не может получить доступ к файлу "имя_файла", потому что он используется другой процесс
что это значит, и что я могу поделать?
6 ответов:
в чем причина?
сообщение об ошибке довольно ясно: вы пытаетесь получить доступ к файлу, и он недоступен, потому что другой процесс (или даже тот же процесс) делает что-то с ним (и он не разрешал никакого совместного использования).
отладка
это может быть довольно легко решить (или очень трудно понять), в зависимости от конкретного сценария. Давайте посмотрим некоторые.
ваш процесс является единственным для доступа к файл
Вы уверены, что другое процесс-это ваш собственный процесс. Если вы знаете, что открываете этот файл в другой части своей программы, то прежде всего вам нужно проверить, правильно ли вы закрываете дескриптор файла после каждого использования. Вот пример кода с этой ошибкой:var stream = new FileStream(path, FileAccess.Read); var reader = new StreamReader(stream); // Read data from this file, when I'm done I don't need it any more File.Delete(path); // IOException: file is in use
к счастью
FileStream
осуществляетIDisposable
, так что это легко обернуть весь ваш код внутриusing
о себе:using (var stream = File.Open("myfile.txt", FileMode.Open)) { // Use stream } // Here stream is not accessible and it has been closed (also if // an exception is thrown and stack unrolled
этот шаблон также гарантирует, что файл не будет оставлен открытым в случае исключений (это может быть причиной использования файла: что-то пошло не так, и никто его не закрыл; см. этот пост для примера).
если все кажется прекрасным (вы уверены, что всегда закрываете каждый открытый файл, даже в случае исключений), и у вас есть несколько рабочих потоков, то у вас есть два варианта: переработать код для сериализации доступа к файлам (не всегда выполнимо и не всегда требуется) или применить шаблон повтора. Это довольно распространенный шаблон для операций ввода-вывода: вы пытаетесь что-то сделать, и в случае ошибки вы ждете и пытаетесь снова (вы спрашивали себя, почему, например, оболочка Windows занимает некоторое время, чтобы сообщить вам, что файл используется и не может быть удален?). В C# это довольно легко реализовать (см. также лучшие примеры о дисковых операций ввода-вывода,сеть и доступ к базе данных).
private const int NumberOfRetries = 3; private const int DelayOnRetry = 1000; for (int i=1; i <= NumberOfRetries; ++i) { try { // Do stuff with file break; // When done we can break loop } catch (IOException e) when (i <= NumberOfRetries) { // You may check error code to filter some exceptions, not every error // can be recovered. Thread.Sleep(DelayOnRetry); } }
обратите внимание на распространенную ошибку, которую мы видим очень часто StackOverflow:
var stream = File.Open(path, FileOpen.Read); var content = File.ReadAllText(path);
в этом случае
ReadAllText()
не получится, потому что файл используется (File.Open()
в строке до). Открывать файл заранее не только не нужно, но и неправильно. То же самое относится ко всемFile
функции, которые не возвращают дескриптор в файл, с которым вы работаете:File.ReadAllText()
,File.WriteAllText()
,File.ReadAllLines()
,File.WriteAllLines()
и другие (например,File.AppendAllXyz()
функции) все откроют и закроют файл сами по себе.ваш процесс это не единственный доступ к этому файлу
Если ваш процесс не только получить доступ к этому файлу, то взаимодействие может быть сложнее. А шаблон повтора поможет (если файл не должен быть открыт кем-либо еще, но это так, то вам нужна утилита, такая как Process Explorer, чтобы проверить кто делает что).способов избежать
если применимо, всегда используйте используя заявления для открытия файлов. Как сказано в предыдущем абзаце он активно поможет вам избежать многих распространенных ошибок (см. этот пост пример как не использовать).
если возможно, попробуйте решить, кому принадлежит доступ к конкретному файлу и централизовать доступ с помощью нескольких известных методов. Если, например, у вас есть файл данных, где ваша программа читает и записывает, то вы должны поместить весь код ввода-вывода внутри одного класса. Это упростит отладку (потому что вы всегда можете поставить точку останова там и посмотреть, кто что делает), а также это будет точка синхронизации (если требуется) для множественного доступа.
не забывайте, что операции ввода-вывода всегда может выйти из строя, например это:
if (File.Exists(path)) File.Delete(path);
если кто-то удаляет файл после
File.Exists()
но доFile.Delete()
, тогда он броситIOException
в месте, где вы можете ошибочно чувствовать себя в безопасности.всякий раз, когда это возможно, применять шаблон повтора, и если вы используете
FileSystemWatcher
, подумайте о переносе действия (потому что вы получите уведомление, но приложение все еще может работать исключительно с этим файлом).дополнительные сценарии
Это не всегда так просто, поэтому вам может потребоваться поделиться доступом с кем-то другим. Если, например, Вы читаете с начала и пишете до конца, у вас есть по крайней мере два варианта.1) доля же
FileStream
с правильными функциями синхронизации (потому что это не потокобезопасный). Смотрите этой и этой сообщения для примера.2) использовать
FileShare
перечисление для указания ОС разрешить другим процессам (или другим частям вашего собственного процесса) одновременно обращаться к одному и тому же файлу.using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.Read)) { }
в этом примере я показал, как открыть файл для записи и Поделиться для чтения; обратите внимание, что при чтении и записи перекрывается, это приводит к неопределенным или недопустимым данным. Это ситуация, которая должна быть решена при чтении. Также обратите внимание, что это не делает доступ к
stream
потокобезопасный, поэтому этот объект не может быть совместно использован с несколькими потоками, если доступ не синхронизирован каким-либо образом (см. предыдущие ссылки). Доступны другие параметры общего доступа, и они открывают более сложные сценарии. Пожалуйста, обратитесь к MSDN для более подробной информации.в общем N процессы могут читать из одного файла все вместе, но только один должен писать, в контролируемом сценарии вы можете даже включите параллельные записи, но это не может быть обобщено в нескольких текстовых абзацах внутри этого ответа.
можно разблокировать файл, используемый другим процессом? Это не всегда безопасно и не так просто, Но да,вполне возможно.
С помощью FileShare Исправлена проблема открытия файла, даже если он открыт другим процессом.
using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite)) { }
возникла проблема при загрузке изображения и не удалось удалить его и найти решение. гл ХФ
//C# .NET var image = Image.FromFile(filePath); image.Dispose(); // this removes all resources //later... File.Delete(filePath); //now works
Я получил эту ошибку, потому что я делал файл.Перейти к пути к файлу без имени файла, необходимо указать полный путь в пункте назначения.
У меня был следующий случай, который вызывает ту же ошибку:
- загрузить файлы на сервер
- затем избавиться от старых файлов после того как они были загружены
большинство файлов были небольшими по размеру, однако некоторые из них были большими, и поэтому попытка удалить их привела к не удается получить доступ к файлу ошибка.
Это было нелегко найти, однако, решение было так же просто, как ожидание "для выполнения задачи для завершения исполнения":
using (var wc = new WebClient()) { var tskResult = wc.UploadFileTaskAsync(_address, _fileName); tskResult.Wait(); }
как указывали другие ответы в этом потоке, чтобы устранить эту ошибку, вам нужно тщательно проверить код, чтобы понять, где файл блокируется.
в моем случае я отправлял файл в виде вложения электронной почты перед выполнением операции перемещения.
таким образом, файл был заблокирован на пару секунд, пока SMTP-клиент не закончил отправку электронной почты.
решение, которое я принял было сначала переместите файл, а затем отправьте электронная почта. это решило проблему для меня.
другим возможным решением, как указывал ранее Хадсон, было бы утилизировать объект после использования.
public static SendEmail() { MailMessage mMailMessage = new MailMessage(); //setup other email stuff if (File.Exists(attachmentPath)) { Attachment attachment = new Attachment(attachmentPath); mMailMessage.Attachments.Add(attachment); attachment.Dispose(); //disposing the Attachment object } }