File.Replace的行为不符合预期

时间:2013-05-12 07:26:46

标签: 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.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

根据MSDN

  

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

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

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

2 个答案:

答案 0 :(得分:1)

很难用发布的代码来解释这一点,这有点像某种第三方实用程序踩到并避免代码所带来的问题。当您为备份文件名传递Nothing时,它将永远不会工作。如果要替换也加载到内存中的可执行文件,则必需。 CLR为程序集创建了一个内存映射文件对象,因此Windows可以根据需要将数据从程序集分页到RAM中。具有很大的优势,这不会占用页面文件中的任何空间。该MMF还对文件进行了硬锁定,因此没有人可以更改文件内容。那将是灾难性的。

这是对文件数据的锁定,而不是文件的目录条目。所以重命名文件仍然有效。这是File.Replace()在提供非空备份文件名时所执行的操作,它重命名程序集,因此您仍然可以创建具有相同名称的文件,而不会遇到锁定问题。您可以删除备份副本,假设您的程序在启动备份时仍具有足够的权限来实际删除该文件。这对于UAC来说这是不寻常的。或者只是不打扰,磁盘空间很便宜,并且有一个备份副本来处理事故是你可以称之为功能的东西。

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

答案 1 :(得分:0)

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