Vb.net 文件。替换未按预期运行

Vb.net 文件。替换未按预期运行,vb.net,file-io,Vb.net,File Io,以下代码应替换可执行文件并重新启动应用程序,这应该可以工作,因为内容应被替换,但不在当前运行的实例中: Dim tmppath As String = System.IO.Path.GetTempFileName Private Sub YesBtn_Click(sender As Object, e As EventArgs) Handles YesBtn.Click Dim client As New WebClient() AddHandler client.Downlo

以下代码应替换可执行文件并重新启动应用程序,这应该可以工作,因为内容应被替换,但不在当前运行的实例中:

Dim tmppath As String = System.IO.Path.GetTempFileName

Private Sub YesBtn_Click(sender As Object, e As EventArgs) Handles YesBtn.Click
    Dim client As New WebClient()
    AddHandler client.DownloadProgressChanged, AddressOf client_ProgressChanged
    AddHandler client.DownloadFileCompleted, AddressOf client_DownloadFileCompleted
    client.DownloadFileAsync(New Uri("https://github.com/Yttrium-tYcLief/Scrotter/raw/master/latest/scrotter.exe"), tmppath)
End Sub

Public Sub client_DownloadFileCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
    File.Replace(tmppath, Application.ExecutablePath, Nothing)
    Application.Restart()
End Sub
根据,

如果不想为要替换的文件创建备份,请将Nothing传递给destinationBackupFileName参数

然而,真正发生的是它确实创建了一个备份(如果.exe是
scrotter.exe
,那么新的备份是
scrotter.exe~RF729c1fe9.TMP
)。此外,在根目录中创建一个名为“False”的新空文件夹


我只想用我的文件替换正在运行的可执行文件,而不需要任何备份或额外的文件夹。有什么想法吗?

我认为只要进程运行,.exe就会被锁定-运行哪个实例不重要。
为了避免这种情况,我会将更新程序放在一个单独的.exe中,并在更新时关闭主应用程序。

用发布的代码很难解释这一点,这闻起来像是某种第三方实用程序介入并避免代码出现问题。如果备份文件名不传递任何内容,则该功能将永远无法工作。如果要替换也加载到内存中的可执行文件,则必须使用。CLR为程序集创建内存映射文件对象,以便Windows可以根据需要将程序集中的数据分页到RAM中。它的最大优点是不会占用分页文件中的任何空间。MMF还对文件进行了硬锁定,因此任何人都无法更改文件内容。那将是灾难性的

这是对文件数据的锁定,而不是文件的目录项。因此重命名文件仍然有效。这就是File.Replace()所做的。当您提供一个非空的备份文件名时,它会重命名程序集,这样您仍然可以创建一个具有相同名称的文件,并且不会因为锁而遇到麻烦。您可以在备份后删除备份副本,前提是您的程序仍然有足够的权限在启动备份时实际删除该文件。这对UAC来说是不寻常的。或者干脆不麻烦了,磁盘空间很便宜,有一个备份副本来处理事故是一种你可以称之为功能的东西


因此,继续正确地使用File.Replace(),使用第三个参数。在调用Replace()之前,请不要忘记删除该备份文件。

是否检查了是否只有在可执行文件运行时才会发生这种情况?我已经用一个简单的文本文件进行了测试,但你所描述的没有发生。我将使用一个非随机文件名在%temp%中创建备份,并在每次我的应用程序启动时检查该文件-如果它在那里,它将被删除。请小心。备份文件必须位于同一驱动器上,以便可以简单地移动而不是复制。%temp%不提供这种保证。样板文件与添加了.bak文件扩展名的目录完全相同。当您要删除或还原备份文件时,还可以更轻松地找到备份文件,这是%temp%无法保证的另一件事,因为它可以更改。因此,在我的可执行文件所在的目录中创建一个.bak文件,然后检查它并在启动时将其删除是否更好?我担心用户可能会干扰它或在那里有另一个文件。我是否可以使用System.IO.Path.GetRandomFilename生成临时文件名,然后将该文件名保存到注册表或其他地方?这比假设.BAK文件是我的应用程序的备份更安全(这个应用程序是可移植的,它不安装到一个目录,尽管我应该考虑这样做)