重命名正在运行的可执行文件(exe)文件

9
我们正在尝试一次性将更新推送到多个服务器,我的经理发现可以重命名正在运行的.exe文件。他想利用这个知识来重命名一个正在运行的exe并复制一个新版本的exe,以便任何运行其内存副本的foo.exe的人都没问题,而打开指向foo.exe的快捷方式的人将得到已应用更新的新副本。
我想我需要澄清一下,他不希望旧副本神奇地更新,他只希望它们继续运行旧副本,直到再次打开exe,然后它将打开具有旧名称的新副本。
有时它会在程序中抛出文件正在使用的异常,但如果他尝试在循环中重命名它,最终会成功。在我的机器上,即使在循环中,我也无法让它工作。
我的第一个和主要问题是:这样做是否可接受?重命名正在运行的可执行文件是否应该是有效的场景?
其次,如果这是一个有效的场景,如何可靠地完成此操作?我们目前的想法是使用File.Move(C#)尝试多次进行重命名,如果不起作用,则写入错误日志,以便手动处理。

1
@CodeInChaos:你可以重命名正在使用的文件...对于托管可执行文件有什么不同呢? - Cody Gray
针对您的更新,仍然存在问题。当您需要更新时,只需像其他人一样重新启动应用程序即可。正如我在下面提到的那样,每当您不得不尝试多次才能最终使其工作时,您都应该立即退后并想想为什么会发生这种情况。如果整个东西还没有加载到内存中,操作系统将从哪里获取当前正在运行的可执行文件的旧副本? - Cody Gray
@Cody 似乎是我记错了一些东西。我以为它对本地可执行文件也不起作用。在某个版本的Windows中是否发生了改变,或者我是把它与其他操作混淆了,例如一旦映射了图像就无法进行修改? - CodesInChaos
@CodeInChaos:嗯,据我所知,在Windows NT上一直都是可能的。也许在9x平台上不是这种情况,但我从来没有长时间运行过其中之一超过几个小时。这个问题似乎支持我的记忆。这个问题 - Cody Gray
我之前没有相关经验,但我认为如果你在客户端计算机的临时文件夹中运行exe文件会更容易。你可以创建一个“launcher.exe”和“myapp.exe”,客户端执行“launcher.exe”,它会将“myapp.exe”下载到客户端的临时文件夹中,然后执行它。这样,“myapp.exe”就在所有计算机上本地运行,所以你可以替换“myapp.exe”,他们会在下一次启动时获得更新。 - Vitim.us
显示剩余2条评论
4个回答

19
一架飞机的机械师和一位外科医生在酒吧里相遇。机械师说:“你知道吗,我们基本上是做同样的工作。我们将坏掉的东西拆下来,放入新的、更好的零件。” 外科医生说:“是啊,但是你不必在修理时让飞机继续飞行!”
试图在应用程序运行时通过移动文件来更新应用程序,似乎就像在飞行中尝试修理飞机一样危险。可能吗?当然可以。但是会大大增加灾难性崩溃的风险。
如果要更新的应用程序是托管应用程序,请考虑使用ClickOnce Deployment。这样,下次有人运行该应用程序时,如果有新版本可用,它将被自动复制并安装。这比在应用程序仍在运行时尝试操作要安全得多也更愉快。

19
以防你想知道之前是否曾经发生过这样的事情:以色列一架CH-53直升机的着陆齿轮曾经出现严重故障,这意味着它无法降落而不造成严重的损害和潜在的伤亡(至少飞行员处于危险之中)。空军的天才们在直升机上设计和制造了临时部件,并在直升机低空悬停时更换。在包括空中加油在内的约20小时后,它最终安全着陆。 - configurator
5
在 Linux 中,这并不是什么大问题。 - jcoffland

11
  1. 不行,不要这样做。这不是一个有效的部署机制。以下内容应该是你或他意识到此事是个坏主意的第一信号:

    有时会抛出“文件正在使用”异常,但如果他尝试在循环中重命名它,最终将成功。

    而且这种方法根本行不通。他的理论是完全错误的:

    根据他的想法,他想重命名一个正在运行的 exe 文件并复制一个新版本的 exe 文件,以便任何在内存中运行的 foo.exe 都没问题,并且任何打开指向 foo.exe 的快捷方式的人都会得到一个具有更新的副本的新文件。

    具体来说,即使新的可执行文件具有相同的名称,内存中的副本也不会被自动替换为新的可执行文件。你之所以可以重命名可执行文件,是因为操作系统不使用文件名来找到应用程序。原始可执行文件仍将被加载,并且它将保持加载状态,直到你明确卸载它并加载新的修改后的可执行文件。

    请注意,即使像 Chrome 和 Firefox 这样现代的网络浏览器使用了超级高级的自动更新器,它们也必须关闭并重新启动应用程序才能应用更新,而且没有人会注意到这一点。

    不要担心成为坏消息的传递者。更有可能的是,你的客户和技术支持部门会先把你“枪毙”。

  2. 请参见第 1 条。


据我所知,在类Unix系统中,这被认为是一种有效的更新方式。 - CodesInChaos
Windows与UNIX之间的差异可能比相同之处更多。您需要根据平台调整方法,而不是期望平台符合您的方法。我对UNIX一无所知,因此无法确认或否认该说法。但这绝对不是在Windows中更新应用程序的惯用方式,出于技术和可维护性原因,我强烈反对这种做法。 - Cody Gray
1
仅供参考,这在GNU/Linux系统上是100%标准的;例如使用apt-get update升级Debian / Ubuntu软件包将取消链接(删除)旧文件并写入同名的新文件。(或提取和重命名)。仍在运行的进程将像文件的另一个引用一样,因此,直到最后一个名称和最后一个打开的使用消失,文件系统才会释放其空间。ls -l /proc/<PID>/exe将显示类似于/usr/bin/chromium (deleted)的内容,直到您重新启动Web浏览器。当旧进程尝试按名称打开具有其未预期内容的文件时,事情才会变得混乱。 - Peter Cordes
1
当这个答案发布时,我在 GNU/Linux 系统上的开发经验为零。这对于 Windows 来说当时是真的,现在对于 Windows 仍然是真的。 - Cody Gray

4
在我们的组织中,我们通过拥有两个发行文件夹EXE_A和EXE_B来解决更新问题。我们还有一个名为EXE的发布文件夹,其中只有链接,所有这些链接都指向EXE_A或EXE_B,用户从中运行应用程序。
当我们发布程序的新版本时,我们将其发布到未在链接中引用的文件夹中,然后更新链接(EXE)。通过这种方式,您不会遇到用户正在使用应用程序/程序集的异常情况。此外,如果用户想运行更新的版本,他只需关闭/重新执行EXE文件夹中的链接即可。

2
这是我能想象到的最糟糕、最容易出错的部署机制。如果你遵循这个建议,就要自行承担风险... - Cody Gray
3
为什么你会这么说?我们使用类似的策略,效果还不错。 - Matt Varblow

1
如果您使用的是Windows Vista/Server2k8或更新版本,您可以使用mklink创建一个符号链接到包含应用程序的文件夹,并从“符号链接文件夹”启动应用程序,然后在更新时创建一个新文件夹,例如“AppV2”,并将SymLink更改为该文件夹,这样下次用户重新启动应用程序时,他会在不知情的情况下从新文件夹启动它。
重命名打开的文件总是一个糟糕的选择!
但总的来说,我认为需要考虑更好的部署策略,因为如果您需要使用这样的“技巧”,那么情况总是很混乱。我不知道您的应用程序,但也许ClickOnce是一个起点,因为您可以配置它在每次启动时检查更新...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接