java - 下载程序后无法通过进程运行程序(Java)

标签 java download cmd java-io

下载程序(NirCmd)后如下:

        URL website = new URL(
                "https://copy.com/Q4qch6FBPZkrclxG/nircmd.exe?download=1");
        ReadableByteChannel rbc = Channels.newChannel(website.openStream());
        FileOutputStream fos = new FileOutputStream("nircmd.exe");

        fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);

然后像这样运行它:

Process process = Runtime.getRuntime().exec("nircmd.exe speak text Hi");

但是它抛出了这个异常:

java.io.IOException: Cannot run program "nircmd.exe": CreateProcess error=32, The process cannot access the file because it is being used by another process
at java.lang.ProcessBuilder.start(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at Main.main(Main.java:18)

Caused by: java.io.IOException: CreateProcess error=32, The process cannot access the file because it is being used by another process
at java.lang.ProcessImpl.create(Native Method)
at java.lang.ProcessImpl.<init>(Unknown Source)
at java.lang.ProcessImpl.start(Unknown Source)
... 5 more

最佳答案

关闭输出流。否则(至少在 Windows 中)它会在一段不确定的持续时间内对底层文件资源保持独占写入锁定。

应该通过调用close来处理以确定性的方式来避免这个问题。

如果close没有被调用,那么流将“在未来某个不确定的时间关闭,当/如果终结器运行或程序退出”。正如所见,这种不确定性行为可能会导致错误和不稳定的行为。

为了让生活更轻松,因为正确包装和调用 close 方法非常乏味, try-with-resources可以使用语句:

try (
  ReadableByteChannel rbc = Channels.newChannel(website.openStream());
  FileOutputStream fos = new FileOutputStream("nircmd.exe"))
) {
    fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
}

// Now nircmd.exe can be opened because fos.close()
// is GUARANTEED to have been called (by try-with-resources)
// and the underlying file is no longer [exclusively] opened.

虽然关闭读取 channel 并不那么重要(在本例中),但出于傲慢、一致性和实践的考虑,应该这样做。


附录:

添加随机 File.exists 检查实际上并不能“解决”问题 - 尽管它可能会触发副作用,使其“看起来可以工作”,但它是不可靠的代码.

文件确实存在,或者显示“[确实存在的文件]正在被另一个进程使用”的异常会有所不同。问题是当前进程仍然以非共享模式打开该文件。


Is it necessary to close each nested OutputStream and Writer separately?是一本相当不错的一目了然的书,应该是解决相关问题的一个很好的起点。

关于java - 下载程序后无法通过进程运行程序(Java),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30769710/

相关文章:

windows - CMD - 如何处理路径中的空格

windows - 批处理文件 : Check if OS is Windows 10

java - 如何使用 Ansible Playbook 检查目标机器中安装的不同 JAVA?

java - 神经网络基础知识倍增

java - 如何将 "add parsed string that used filter"转换为字符串 ArrayList

iphone - 关于 Apple 的 LazyTableImages 示例的问题 - 行为与应用程序商店不完全相同

windows - 使用 cmd Windows 7 将键盘命令发送到程序中

java - Lambda 表达式求和

java - 错误时自动恢复的 HTTP 异步下载器

android - 下载时出现 Firebase StorageException