VB.Net 3.5 Controllare se il file è in uso
Domanda
Ho un programma di aggiornamento che è completamente indipendente dalla mia principale dell'applicazione. Corro l'update.exe per aggiornare l'app.exe. Per verificare se il file è in uso, lo sposto in un altro file e prendere un errore se è in uso. Se nessun problema occurr rinomino indietro. Almeno questo era il mio piano ...
Programma principale:
app.exe Programma di aggiornamento: update.exe
Questo programma viene utilizzato attraverso la rete senza prestazioni in esecuzione. Così, gli utenti sono letteralmente in esecuzione il file EXE in rete sul loro macchina.
Ho bisogno di aggiornare l'app.exe quando l'update.exe ha eseguito. Per verificare se l'app.exe era ancora in uso stavo avvolgendo la segue in un try / catch per vedere se non è riuscito:
IO.File.Move (upddir & "\ app.exe", upddir & "\ app.exe.tst")
IO.File.Move (upddir & "\ app.exe.tst", upddir & "\ app.exe")
La cosa divertente è, anche se l'app.exe è in esecuzione, la mossa può rinominarlo al app.exe.tst senza alcun errore. Posso anche continuare nell'applicazione senza errori.
Ho pensato che ero fuori di testa, così ho avuto un altro sguardo programmatore a questo e ha verificato quello che ho detto sopra.
Quindi, abbiamo provato questo avvolto in un tentativo di cattura:
readfile fioco come nuovo FileStream (upddir & "\ app.exe", FileMode.Open, FileAccess.Read, FileShare.NONE)
readfile.Dispose ()
Ho messo la condivisione file come nessuno che, almeno ho pensato che sarebbe, mostrano che c'era qualcuno nel file.
Si continuava senza alcun errore.
Qualcuno sa il motivo per cui posso rinominare un file in uso? Inoltre, c'è un modo migliore per farlo che quello che sto facendo ora?
Grazie! Eroc
Soluzione
Si potrebbe fare quanto segue per verificare se l'applicazione ha altre istanze in esecuzione:
Process.GetProcessesByName("app.exe", "Machine1").Length > 0
che è un modo più appropriato di verificare se l'applicazione è in esecuzione.
Dai un'occhiata alla File.Move documentazione MSDN. E 'dettagli quali eccezioni sono gettati. Hai il permesso di rinominare un file exe, anche se è in uso in Vista.
Altri suggerimenti
Lo stesso codice utilizzando "utilizzando":)
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
Che cosa si potrebbe fare è sostituire l'applicazione di destinazione con un exe custode.
Questa custode quindi genera l'applicazione di destinazione, ma crea anche un file bloccato in una posizione condivisa. Il blocco viene rilasciato e il file viene eliminato quando le uscite app.
Quindi, prima di aggiornare l'app.exe, si controlla ci sono eventuali file bloccati nella posizione condivisa, se ci sono file bloccati allora l'app.exe è in uso.
Il programma custode potrebbe essere un'applicazione finestra di meno, il seguente console app fa più o meno quello che deve fare
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");
}
}
Il programma di aggiornamento cerca quindi per tutti "AppLock_ *" file, e tenta di aprirli con un blocco di scrittura, se non è possibile ottenere un blocco di scrittura su uno di essi, l'exe è in uso.
Spero che questo aiuti.
Questo è quello che ho finito per fare. La scansione della rete non ha funzionato su una rete peer-to-peer. Essa non ha risolto gli altri computer a tutti.
In ogni caso, qui è:
Private Sub CheckFileIfFileIsInUse (ByVal thefilename As String)
Prova
'Sul sistema operativo Vista è possibile rinominare un file che è in uso
'La 'in uso' del file originale segue il nuovo nome del fileDim 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
Spero che questo aiuti la prossima persona.
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