VB.Net 3.5 Verifique se o arquivo está em uso
Pergunta
Eu tenho um programa de atualização que é completamente independente do meu aplicativo principal. Eu executar o Update.exe para atualizar o app.exe. Para verificar se o arquivo está em uso, eu movê-lo para outro arquivo e pegar um erro se ele estiver em uso. Se nenhum problema occurr eu renomeá-lo de volta. Pelo menos isso era o meu plano ...
Main programa: app.exe
programa Update: update.exe
Este programa é utilizado pela rede sem quaisquer serviços em execução. Assim, os usuários é literalmente correr o exe através da rede no mudando máquina.
Eu preciso atualizar o app.exe quando o update.exe foi executado. Para verificar para ver se o app.exe ainda estava em uso Eu estava encerrando o seguinte em um try / catch para ver se ele falhou:
IO.File.Move (upddir & "\ app.exe", upddir & "\ app.exe.tst")
IO.File.Move (upddir & "\ app.exe.tst", upddir & "\ app.exe")
O engraçado é que, mesmo se o app.exe está em execução, o movimento pode renomeá-lo para o app.exe.tst sem qualquer erro. Posso até continuar na aplicação sem erros.
Eu pensei que estava fora da minha mente, então eu tinha um outro olhar programador para isso e ele verificou que eu disse acima.
Então, nós tentamos isso envolto em um try catch:
Dim readfile As New FileStream (upddir & "\ app.exe", FileMode.Open, FileAccess.Read, FileShare.NONE)
readfile.Dispose ()
Eu coloquei o fileshare como nenhum que, pelo menos eu pensei que seria, mostram que havia alguém no arquivo.
Ele ainda continuou sem qualquer erro.
Alguém sabe por que eu posso renomear um arquivo em uso? Além disso, há uma maneira melhor de fazer isso do que o que eu estou fazendo agora?
Obrigado! Eroc
Solução
Você pode fazer o seguinte para verificar se o aplicativo tem outras instâncias em execução:
Process.GetProcessesByName("app.exe", "Machine1").Length > 0
Qual é a forma mais adequada de verificar se o aplicativo está sendo executado.
Tenha um olhar em File.Move documentação MSDN. Ele detalha o que exceções são lançadas. Você tem permissão para mudar o nome de um exe, mesmo se ele estiver em uso no Vista.
Outras dicas
O mesmo código usando "usando":)
Public Function FileInUse(ByVal sFile As String) As Boolean
Dim thisFileInUse As Boolean = False
If System.IO.File.Exists(sFile) Then
Try
Using f As New IO.FileStream(sFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
' thisFileInUse = False
End Using
Catch
thisFileInUse = True
End Try
End If
Return thisFileInUse
End Function
O que você poderia fazer é substituir o aplicativo de destino com um exe zelador.
Esta zelador, em seguida, gera a aplicação de destino, mas também cria um arquivo bloqueado em um local compartilhado. A trava é liberada e o arquivo é excluído quando sai do aplicativo.
Então, antes de atualizar o app.exe, você verificar existem arquivos bloqueados no local compartilhado, se houver arquivos bloqueados em seguida, o app.exe está em uso.
O programa zelador poderia ser um aplicativo de janela menos, a seguinte aplicação de console faz muito bem o que ele precisa fazer
class Program
{
static string lockFileName;
static System.IO.StreamWriter lockFileWrtier;
static void Main(string[] args)
{
lockFileName = "AppLock_" + System.IO.Path.GetRandomFileName();
lockFileWrtier = new System.IO.StreamWriter(lockFileName);
System.Diagnostics.Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.EnableRaisingEvents = true;
p.Exited += new EventHandler(p_Exited);
p.Start();
Console.WriteLine("Press any key to stop");
Console.ReadKey();
}
static void p_Exited(object sender, EventArgs e)
{
lockFileWrtier.Dispose();
System.IO.File.Delete(lockFileName);
Console.WriteLine("Process has exited");
}
}
O atualizador em seguida, olha para todos "AppLock_ *" arquivos e tentativas de abri-los com um bloqueio de gravação, se não for possível obter um bloqueio de gravação em um deles, o exe está em uso.
Espero que isso ajude.
Isto é o que eu acabei fazendo. A digitalização em rede não funciona em uma rede peer-to-peer. Não resolver os outros computadores em tudo.
De qualquer forma, aqui está:
Private Sub CheckFileIfFileIsInUse (ByVal thefilename As String)
tente
'Sobre o sistema operacional Vista, você pode renomear um arquivo que está em uso
'The 'em uso' do arquivo original segue o novo nome de arquivo
Dim testfile As String = thefilename & ".tst"<br /> If IO.File.Exists(testfile) Then<br /> IO.File.Delete(testfile)<br /> End If<br /> ' so we have to rename it to something else<br /> IO.File.Move(thefilename, testfile)<br /> ' copy it back to the original file name in case something <br />breaks ' this just keeps them in working order if it does<br /> IO.File.Copy(testfile, thefilename)<br /> ' then we try to delete the original file that could be in use <br /> ' which will return an 'in use' error at this point<br /> If IO.File.Exists(testfile) Then<br /> IO.File.Delete(testfile)<br /> End If<br /> Catch ex As Exception<br /> 'throw it to the originating method<br /> Throw<br /> End Try<br />
End Sub
Hope isso ajuda a próxima pessoa.
Public Function FileInUse(ByVal sFile As String) As Boolean
If System.IO.File.Exists(sFile) Then
Try
Dim F As Short = FreeFile()
FileOpen(F, sFile, OpenMode.Binary, OpenAccess.ReadWrite, OpenShare.LockReadWrite)
FileClose(F)
Catch
Return True
End Try
End If
End Function