Eu tenho algum código e quando ele executa, lança um IOException
, dizendo que
O processo não pode acessar o arquivo 'filename' porque está sendo usado por outro processo
O que isso significa e o que posso fazer sobre isso?
c#
.net
language-agnostic
ioexception
Adriano Repetti
fonte
fonte
Respostas:
Qual é a causa?
A mensagem de erro é bastante clara: você está tentando acessar um arquivo e não está acessível porque outro processo (ou mesmo o mesmo) está fazendo algo com ele (e não permitiu nenhum compartilhamento).
Depuração
Pode ser bem fácil de resolver (ou muito difícil de entender), dependendo do seu cenário específico. Vamos ver alguns.
Seu processo é o único a acessar esse arquivo.
Você tem certeza de que o outro processo é o seu próprio processo. Se você sabe que abre esse arquivo em outra parte do seu programa, primeiro precisa verificar se fecha corretamente o identificador de arquivo após cada uso. Aqui está um exemplo de código com esse bug:
Felizmente
FileStream
implementaIDisposable
, portanto, é fácil agrupar todo o seu código dentro de umausing
instrução:Esse padrão também garantirá que o arquivo não seja deixado aberto em caso de exceções (pode ser o motivo pelo qual o arquivo está sendo usado: algo deu errado e ninguém o fechou; veja esta postagem como exemplo).
Se tudo parecer correto (você sempre fecha todos os arquivos abertos, mesmo em exceções) e possui vários threads de trabalho, há duas opções: refazer seu código para serializar o acesso a arquivos (nem sempre é factível e nem sempre desejado) ou aplique um padrão de repetição . É um padrão bastante comum para operações de E / S: você tenta fazer algo e, em caso de erro, espera e tenta novamente (você se perguntou por que, por exemplo, o Windows Shell leva algum tempo para informar que um arquivo está em uso e não pode ser excluído?). Em C #, é muito fácil de implementar (consulte também melhores exemplos sobre E / S de disco , rede e acesso a banco de dados ).
Observe um erro comum que vemos frequentemente no StackOverflow:
Nesse caso
ReadAllText()
, falhará porque o arquivo está em uso (File.Open()
na linha anterior). Abrir o arquivo antecipadamente não é apenas desnecessário, mas também errado. O mesmo se aplica a todas asFile
funções que não retornam um identificador para o arquivo que você está trabalhando com:File.ReadAllText()
,File.WriteAllText()
,File.ReadAllLines()
,File.WriteAllLines()
e outros (comoFile.AppendAllXyz()
funções) tudo vai abrir e fechar o arquivo por si mesmos.Seu processo não é o único a acessar esse arquivo
Se o seu processo não é o único a acessar esse arquivo, a interação pode ser mais difícil. Um padrão de nova tentativa ajudará (se o arquivo não puder ser aberto por mais ninguém, mas sim, você precisará de um utilitário como o Process Explorer para verificar quem está fazendo o que ).
Maneiras de evitar
Quando for o caso, use sempre usando declarações aos arquivos abertos. Como dito no parágrafo anterior, ele ajudará ativamente a evitar muitos erros comuns (consulte esta postagem para um exemplo de como não usá-lo ).
Se possível, tente decidir quem possui o acesso a um arquivo específico e centralize o acesso por meio de alguns métodos conhecidos. Se, por exemplo, você tiver um arquivo de dados em que seu programa leia e grave, você deve colocar todo o código de E / S dentro de uma única classe. Isso tornará a depuração mais fácil (porque você sempre pode colocar um ponto de interrupção lá e ver quem está fazendo o que) e também será um ponto de sincronização (se necessário) para acesso múltiplo.
Não se esqueça que as operações de E / S sempre podem falhar, um exemplo comum é este:
Se alguém excluir o arquivo depois,
File.Exists()
mas antesFile.Delete()
, ele lançará um arquivoIOException
em um local onde você se sentirá errado.Sempre que possível, aplique um padrão de nova tentativa e, se estiver usando
FileSystemWatcher
, adie a ação (porque você será notificado, mas um aplicativo ainda poderá estar trabalhando exclusivamente com esse arquivo).Cenários avançados
Nem sempre é tão fácil, então você pode precisar compartilhar o acesso com outra pessoa. Se, por exemplo, você está lendo do começo e escrevendo até o fim, tem pelo menos duas opções.
1) compartilhe o mesmo
FileStream
com as funções de sincronização adequadas (porque não é seguro para threads ). Veja este e este post para um exemplo.2) use a
FileShare
enumeração para instruir o SO a permitir que outros processos (ou outras partes do seu próprio processo) acessem o mesmo arquivo simultaneamente.Neste exemplo, mostrei como abrir um arquivo para escrever e compartilhar para leitura; observe que, ao ler e escrever sobreposições, isso resulta em dados indefinidos ou inválidos. É uma situação que deve ser tratada ao ler. Observe também que isso não torna o acesso ao
stream
thread seguro, portanto, esse objeto não pode ser compartilhado com vários threads, a menos que o acesso seja sincronizado de alguma forma (consulte os links anteriores). Outras opções de compartilhamento estão disponíveis e abrem cenários mais complexos. Por favor, consulte o MSDN para mais detalhes.Em geral, os processos N podem ler o mesmo arquivo todos juntos, mas apenas um deve escrever; em um cenário controlado, você pode até ativar gravações simultâneas, mas isso não pode ser generalizado em poucos parágrafos de texto nesta resposta.
É possível desbloquear um arquivo usado por outro processo? Nem sempre é seguro e nem tão fácil, mas sim, é possível .
fonte
File.Create(path)
, deve adicionar.Close()
no final antes de escrever nele. Existem armadilhas como essa, além deusing
instruções para gravar os arquivos e depois excluí-los. Você deve postar o código na sua pergunta sobre como você está criando e excluindo seu arquivo. Mas provavelmente se alinha com o mencionado acima.Directory.SetCreationTimeUTC()
mas falha quando o File Explorer está aberto, alegando que o diretório está sendo acessado por outro processo. Como devo lidar com essa situação?O uso do FileShare corrigiu meu problema de abrir o arquivo, mesmo que ele fosse aberto por outro processo.
fonte
Ocorreu um problema ao fazer upload de uma imagem e não pôde excluí-la e encontrou uma solução. gl hf
fonte
Eu recebi esse erro porque estava executando o File.Move para um caminho de arquivo sem um nome de arquivo, preciso especificar o caminho completo no destino.
fonte
O erro indica que outro processo está tentando acessar o arquivo. Talvez você ou alguém o tenha aberto enquanto você tenta escrever nele. "Ler" ou "Copiar" geralmente não causa isso, mas escrever nele ou chamar excluir nele causaria.
Existem algumas coisas básicas para evitar isso, como outras respostas mencionaram:
Nas
FileStream
operações, coloque-o em umusing
bloco com umFileShare.ReadWrite
modo de acesso.Por exemplo:
Observe que
FileAccess.ReadWrite
não é possível se você usarFileMode.Append
.Corri esse problema quando estava usando um fluxo de entrada para fazer isso
File.SaveAs
quando o arquivo estava em uso. No meu caso, descobri que na verdade não precisava salvá-lo no sistema de arquivos, então acabei removendo isso, mas provavelmente poderia ter tentado criar um FileStream em umausing
declaração comFileAccess.ReadWrite
, assim como o código acima.Salvar seus dados como um arquivo diferente e voltar para excluir o antigo quando ele não estiver mais em uso, em seguida, renomear aquele que foi salvo com sucesso no nome do original é uma opção. Como você testa o arquivo em uso é realizado através do
linha no meu código abaixo e pode ser feito em um serviço do Windows, em loop, se você tiver um arquivo específico que deseja assistir e excluir regularmente quando quiser substituí-lo. Se você nem sempre tiver o mesmo arquivo, um arquivo de texto ou tabela de banco de dados poderá ser atualizado para que o serviço sempre verifique nomes de arquivos e execute essa verificação de processos e, posteriormente, execute o processo de eliminação e eliminação, conforme descrevo na próxima opção. Observe que você precisará de um nome de usuário e senha de conta com privilégios de administrador no computador especificado, é claro, para executar a exclusão e o término dos processos.
Quando você não souber se um arquivo estará em uso quando estiver tentando salvá-lo, poderá fechar todos os processos que poderiam estar em uso, como o Word, se for um documento do Word, antes do salvamento.
Se for local, você pode fazer isso:
Se for remoto, você pode fazer o seguinte:
Onde
txtUserName
está na forma deDOMAIN\user
.Digamos que você não saiba o nome do processo que está bloqueando o arquivo. Então, você pode fazer isso:
Note-se que
file
deve ser o caminho UNC:\\computer\share\yourdoc.docx
para que aProcess
descobrir o computador é ligado ep.MachineName
seja válido.Abaixo está a classe que essas funções usam, que requer a adição de uma referência
System.Management
. O código foi originalmente escrito por Eric J .:fonte
Como outras respostas neste tópico apontaram, para resolver esse erro, é necessário inspecionar cuidadosamente o código, para entender onde o arquivo está sendo bloqueado.
No meu caso, eu estava enviando o arquivo como um anexo de email antes de executar a operação de movimentação.
Portanto, o arquivo ficou bloqueado por alguns segundos até o cliente SMTP terminar de enviar o email.
A solução que eu adotei foi mover o arquivo primeiro e depois enviar o email. Isso resolveu o problema para mim.
Outra solução possível, como apontado anteriormente por Hudson, seria descartar o objeto após o uso.
fonte
File.Move()
, não funcionará e causará o mesmo erro. Se apenas adicionar um arquivo a um email, não acho que ocorra algum erro durante o uso durante aAttachments.Add()
operação, porque esta é apenas uma operação de cópia. Se, por algum motivo, você puder copiá-lo para um diretório Temp, anexe a cópia e exclua o arquivo copiado posteriormente. Mas acho que, se o OP quiser modificar um arquivo e usá-lo, esse tipo de solução (da qual você não mostrou o código, apenas a parte anexa) funcionaria..Dispose()
é sempre uma boa ideia, mas não é relevante aqui, a menos que o arquivo seja aberto em uma operação anterior.Eu tive o seguinte cenário que estava causando o mesmo erro:
A maioria dos arquivos era pequena, no entanto, alguns eram grandes e, portanto, a tentativa de excluir os arquivos resultou no erro de acesso ao arquivo .
Não foi fácil encontrar, no entanto, a solução era tão simples quanto Aguardar "a tarefa concluir a execução":
fonte
Meu código abaixo resolve esse problema, mas sugiro Antes de tudo, você precisa entender o que está causando esse problema e tentar a solução que você pode encontrar alterando o código
Posso dar outra maneira de resolver esse problema, mas a melhor solução é verificar sua estrutura de codificação e tentar analisar o que faz isso acontecer, se você não encontrar nenhuma solução, poderá seguir este código abaixo
fonte
GC.*()
, provavelmente terá outros problemas com seu código. 2) A mensagem é localizada e frágil , use o HRESULT. 3) Você pode dormir comTask.Delay()
(e dez segundos é excessivo em muitos casos). 4) Você não tem uma condição de saída: esse código pode travar o forver. 5) Você definitivamente não precisagoto
aqui. 6) PegarException
é geralmente uma má idéia, neste caso também porque ... 6) Se algo mais acontecer, você estará engolindo o erro.GC.Collect()
foi ao lidar com alguns objetos COM.