none
Excluir arquivo usado por outro processo RRS feed

  • Pergunta

  • Bom dia,

    eu estou começando a usar a BoletoNet.dll e quando estoura alguma exceção o arquivo não é excluído. Se tento executar o comando "System.IO.File.Delete(diretorio/nome_arquivo)" aparece a seguinte mensagem:

    The process cannot access the file 'diretorio/nome_arquivo' because it is being used by another process.

    Eu já fiz pesquisas na net e o povo diz pra usar using(StreamWriter..) ou Dispose(), mas nesse caso é uma DLL, não tem como editar. Como posso fazer pra excluir o arquivo?

    quinta-feira, 23 de abril de 2015 12:17

Respostas

  • Boa tarde, Eugenio

    O problema neste caso é que existe um processo ativo que está prendendo o arquivo, como descrito pela mensagem de erro. O que deve ser feito é "matar" este processo, ou árvore de processos para liberar o arquivo para a exclusão.

    Neste link tem um exemplo de como descobrir os processos que estão bloqueando o acesso ao arquivo:

    http://stackoverflow.com/questions/860656/using-c-how-does-one-figure-out-what-process-locked-a-file

    Espero que ajude.

    Abraço

    quinta-feira, 23 de abril de 2015 17:28
  • E parece haver um utilitário melhor ainda chamando Handle. Você especifica o caminho do arquivo e ele retorna os processos que estão usando.

    Handle

    Também não encontrei exemplos. Mas estou tentando implementar algo...


    Herbert Lausmann

    Usando o Handle fica super fácil em comparação com os outros códigos.

    É só baixar ele, copiar o arquivo handle.exe para o diretório da sua aplicação.

    Código de exemplo:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Diagnostics;
    using System.Text.RegularExpressions;
    
    namespace Open_Files
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                OpenFileDialog dialog = new OpenFileDialog();
                dialog.ShowDialog();
                foreach (Process pr in FileSystem.GetProcessLockingFile(dialog.FileName))
                    pr.Kill();
            }
        }
        public static class FileSystem
        {
            public static IEnumerable<Process> GetProcessLockingFile(string filePath)
            {
                string currentDirectory = System.IO.Path.GetDirectoryName(new Uri(
                    System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath);
                string handlePath = currentDirectory + "\\handle.exe";
                ProcessStartInfo handleStarting = new ProcessStartInfo(handlePath);
                handleStarting.UseShellExecute = false;
                handleStarting.RedirectStandardOutput = true;
                handleStarting.Arguments = "\"" + filePath + "\" /accepteula";
                handleStarting.Verb = "runas";
                handleStarting.CreateNoWindow = true;
                Process handleProcess = Process.Start(handleStarting);
                handleProcess.WaitForExit();
    
                string outputTool = handleProcess.StandardOutput.ReadToEnd();
    
                string matchPattern = @"(?<=\s+pid:\s+)\b(\d+)\b(?=\s+)";
                foreach (Match match in Regex.Matches(outputTool, matchPattern))
                {
                    yield return Process.GetProcessById(int.Parse(match.Value));
                }
                yield break;
            }
        }
    }

    Testei aqui com um arquivo que estava sendo descompactado pelo WinRar e funcionou certinho.


    Herbert Lausmann

    • Marcado como Resposta Eugenio Junior quinta-feira, 30 de abril de 2015 12:23
    quarta-feira, 29 de abril de 2015 21:21

Todas as Respostas

  • Boa tarde, Eugenio

    O problema neste caso é que existe um processo ativo que está prendendo o arquivo, como descrito pela mensagem de erro. O que deve ser feito é "matar" este processo, ou árvore de processos para liberar o arquivo para a exclusão.

    Neste link tem um exemplo de como descobrir os processos que estão bloqueando o acesso ao arquivo:

    http://stackoverflow.com/questions/860656/using-c-how-does-one-figure-out-what-process-locked-a-file

    Espero que ajude.

    Abraço

    quinta-feira, 23 de abril de 2015 17:28
  • Boa noite Demetrio,

    eu vou dar uma olhada nesse link que vc me passou e depois dou o retorno. Obrigado por enquanto.

    sexta-feira, 24 de abril de 2015 22:47
  • Demetrio,

    eu não estou sabendo usar esse código. Eu copiei o código do Lain Ballard do link que vc passou e no sistema estou chamando o método "GetFilesLockedBy" passando como parâmetro o processo atual que está operando o arquivo. Pelo que parece esse método interrompe e aborta o processo, apesar de que o nome do método é "Obter arquivos de bloqueio".

    É esse o método a ser chamado ou outro?

    quarta-feira, 29 de abril de 2015 12:29
  • Pelo que eu entendi, você terá que chamar dessa forma:

    List<Process> lstProcs = GetProcessesLockingFile(filepath);
    foreach(Process p in lstProcs)
    {
        p.Kill();
    }


    Att. Andre de Mattos Ferraz

    quarta-feira, 29 de abril de 2015 12:54
  • Andre, com base no teu exemplo eu fiz o seguinte:

    Process pr = new Process();

    pr = System.Diagnostics.Process.GetCurrentProcess();

    pr.Kill();

    Só que daí ele finaliza o sistema que está processando o arquivo. Então na verdade teria que só liberar o arquivo da memória para poder excluir ele. Acho que seria isso né?

    O estranho é que é o próprio sistema que gera o arquivo através de uma DLL (que não tem tratamento para excluir o arquivo) e o mesmo processo não consegue excluir o arquivo.
    quarta-feira, 29 de abril de 2015 13:13
  • Em alguns foruns eu vi comentarios sobre esses metodos:

    GC.Collect();
    GC.WaitForPendingFinalizers();

    Só que não fez diferença no meu caso. Isso ajuda em alguma coisa?

    quarta-feira, 29 de abril de 2015 14:20
  • Manda um print dos processos em execução quando acontece a exceção.

    Att. Andre de Mattos Ferraz

    quarta-feira, 29 de abril de 2015 14:22
  • Essa é a lista de todos os processos que dá pra consultar dentro do método "GetProcessesLockingFile".

    O processo atual do sistema é o que está destacado (uso o método "System.Diagnostics.Process.GetCurrentProcess()" para obter o processo atual).

    Será que é algum outro processo que precisa ser excluído para liberar o arquivo?
    quarta-feira, 29 de abril de 2015 16:05
  • Qual o valor do filepath (está com muitos processos, estranho... que arquivo é esse)? A aplicação é desktop ou web?

    Att. Andre de Mattos Ferraz

    quarta-feira, 29 de abril de 2015 16:45
  • O Filepath eu passo o diretório com o nome do arquivo. Nesse caso seria "C:\USERS\EUGENIO JUNIOR\DESKTOP\REMESSA29042015.REM".

    É um arquivo TXT normal, apenas com extensão .REM.

    A aplicação é desktop.

    quarta-feira, 29 de abril de 2015 16:57
  • Entao, isso que é estranho, pq tem tantos processos utilizando ele? Na lista que tu passou tem o Chrome, Skype...

    Eu não sei se esse código que está no stackoverflow funciona, ja tentou testar com outros arquivos?


    Att. Andre de Mattos Ferraz

    quarta-feira, 29 de abril de 2015 17:21
  • Acho que vc não reparou, mas esse monte de processos são provenientes do comando "Process.GetProcesses()" que atualiza a variável "processListSnapshot" com todos os processos do Windows, tudo dentro do método "GetProcessesLockingFile".

    Depois tem um loop que percorre essa lista e chama o método "GetFilesLockedBy" passando cada processo por parâmetro.

    Eu não sei se esse código é viável.

    Você não passou por caso assim? Não tem outra forma mais fácil?

    quarta-feira, 29 de abril de 2015 17:32
  • Eu vi o código ele pega todos os processos e verifica se o processo está travando o arquivo (filepath que vc passou). Mas a sua lista está estranha pois é como se ele tivesse retornando todos os processos e todos eles estão dando lock no arquivo.

    public static List<Process> GetProcessesLockingFile(string filePath)
            {
                var procs = new List<Process>();
    
                var processListSnapshot = Process.GetProcesses();
                foreach (var process in processListSnapshot)
                {
                    if (process.Id <= 4) { continue; } // system processes
                    var files = GetFilesLockedBy(process);
                    if (files.Contains(filePath)) procs.Add(process);
                }
                return procs;
            }


    Att. Andre de Mattos Ferraz

    quarta-feira, 29 de abril de 2015 17:37
  • Bom dia,

    eu estou começando a usar a BoletoNet.dll e quando estoura alguma exceção o arquivo não é excluído. Se tento executar o comando "System.IO.File.Delete(diretorio/nome_arquivo)" aparece a seguinte mensagem:

    The process cannot access the file 'diretorio/nome_arquivo' because it is being used by another process.

    Eu já fiz pesquisas na net e o povo diz pra usar using(StreamWriter..) ou Dispose(), mas nesse caso é uma DLL, não tem como editar. Como posso fazer pra excluir o arquivo?

    Olá,

    Vi sua questão e sei de uma possível solução mais simples. Qual a versão do Windows você está visando para seu aplicativo? Se for do Vista em diante, o que estou pensando será viável....


    Herbert Lausmann

    quarta-feira, 29 de abril de 2015 17:46
  • Boa tarde Herbert,

    os requisitos básicos pra rodar o sistema é do Windows Vista ou superior. Qual seria a solução?

    quarta-feira, 29 de abril de 2015 20:00
  • Boa tarde Herbert,

    os requisitos básicos pra rodar o sistema é do Windows Vista ou superior. Qual seria a solução?

    Então, as versões do Windows a partir do Vista, incluem um utilitário chamado openfiles.exe na pasta System32.

    Teoricamente, você pode usá-lo para retornar uma lista de arquivos abertos por um determinado processo, conforme o que vi nos links abaixo.

    Openfiles

    scripting - Powershell script to check application that's locking a file? - Stack Overflow

    Então você poderia pegar a lista de arquivos abertos por cada processo em execução e então verificar qual processo abriu o seu arquivo para poder fecha-lo.

    Infelizmente não encontrei um exemplo de código...


    Herbert Lausmann

    quarta-feira, 29 de abril de 2015 20:20
  • E parece haver um utilitário melhor ainda chamando Handle. Você especifica o caminho do arquivo e ele retorna os processos que estão usando.

    Handle

    Também não encontrei exemplos. Mas estou tentando implementar algo...


    Herbert Lausmann

    quarta-feira, 29 de abril de 2015 20:33
  • Só que assim.. o sistema começou a gerar o arquivo TXT através da DLL e ele seria o processo atual que está trabalhando com o arquivo, correto?

    Se for finalizar esse processo vai encerrar a aplicação, não seria isso?

    quarta-feira, 29 de abril de 2015 20:36
  • Depende, pode ser que a dll crie um outro processo. Tenta verificar na execução do programa na parte que ele invoca a dll se aparece algum novo processo no seu task manager.

    Att. Andre de Mattos Ferraz

    quarta-feira, 29 de abril de 2015 20:56
  • E parece haver um utilitário melhor ainda chamando Handle. Você especifica o caminho do arquivo e ele retorna os processos que estão usando.

    Handle

    Também não encontrei exemplos. Mas estou tentando implementar algo...


    Herbert Lausmann

    Usando o Handle fica super fácil em comparação com os outros códigos.

    É só baixar ele, copiar o arquivo handle.exe para o diretório da sua aplicação.

    Código de exemplo:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Diagnostics;
    using System.Text.RegularExpressions;
    
    namespace Open_Files
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                OpenFileDialog dialog = new OpenFileDialog();
                dialog.ShowDialog();
                foreach (Process pr in FileSystem.GetProcessLockingFile(dialog.FileName))
                    pr.Kill();
            }
        }
        public static class FileSystem
        {
            public static IEnumerable<Process> GetProcessLockingFile(string filePath)
            {
                string currentDirectory = System.IO.Path.GetDirectoryName(new Uri(
                    System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath);
                string handlePath = currentDirectory + "\\handle.exe";
                ProcessStartInfo handleStarting = new ProcessStartInfo(handlePath);
                handleStarting.UseShellExecute = false;
                handleStarting.RedirectStandardOutput = true;
                handleStarting.Arguments = "\"" + filePath + "\" /accepteula";
                handleStarting.Verb = "runas";
                handleStarting.CreateNoWindow = true;
                Process handleProcess = Process.Start(handleStarting);
                handleProcess.WaitForExit();
    
                string outputTool = handleProcess.StandardOutput.ReadToEnd();
    
                string matchPattern = @"(?<=\s+pid:\s+)\b(\d+)\b(?=\s+)";
                foreach (Match match in Regex.Matches(outputTool, matchPattern))
                {
                    yield return Process.GetProcessById(int.Parse(match.Value));
                }
                yield break;
            }
        }
    }

    Testei aqui com um arquivo que estava sendo descompactado pelo WinRar e funcionou certinho.


    Herbert Lausmann

    • Marcado como Resposta Eugenio Junior quinta-feira, 30 de abril de 2015 12:23
    quarta-feira, 29 de abril de 2015 21:21
  • Herbert, fiz o teste com esse código muito louco que eu não conseguiria fazer.. kkk.. e pegou o processo que está usando o arquivo. Porém, o processo é o próprio sistema que está gerando o arquivo. E usando o método "kill" ele fecha o sistema.

    Eu baixei o código fonte do Boleto.Net e vi que não tem o Close e Dispose no Exception para fechar o arquivo que está sendo processado. Por isso o arquivo não é liberado e não consegue ser usado enquanto não fechar o sistema. Esses comandos só tem dentro do Try. Eu acho que vou corrigir esse código fonte e usá-lo no lugar da DLL.

    O que acha?

    quinta-feira, 30 de abril de 2015 11:56
  • Se vc tem acesso a esse código é o melhor a se fazer.

    Att. Andre de Mattos Ferraz

    quinta-feira, 30 de abril de 2015 11:59
  • Valeu pessoal, muito obrigado pela ajuda!

    quinta-feira, 30 de abril de 2015 12:22