已安装的 Java 程序提交批处理文件但它不执行。从命令窗口执行相同的可执行文件有效

Posted

技术标签:

【中文标题】已安装的 Java 程序提交批处理文件但它不执行。从命令窗口执行相同的可执行文件有效【英文标题】:Installed Java program submits batch file but it does not execute. Executing the same executable from the command window works 【发布时间】:2021-08-22 00:11:24 【问题描述】:

我将一个 JAVA jar 程序转换为 .exe,然后使用 INNO Setup 创建了一个安装程序。该程序安装并运行,除了最后我提交一个 dos 命令来执行批处理文件以复制一些文件。如果我通过双击与之关联的文件来运行已安装的程序。程序运行成功,但批处理文件没有运行。如果我打开一个命令窗口并从命令行执行相同的程序,它运行成功,批处理文件运行成功。

运行批处理文件的方法是。

    public static int  moveAside()

    System.out.println("----MoveAside: start: " + UserDir + " TCDir: " + TCDir);
   try
   
       String pathx = "\"" + UserDir + "\"";
       String newFileName = FilenameIn.replaceAll("/","\\\\");
       String newTCDir = TCDir.replaceAll("/","\\\\");
       String squote = "\"";
       String path = "cmd \"/c/q\" start  \"\" "   + pathx + "\\moveAside.bat " +   "C:\\IronLayer\\PERPLXDAM\\"  + " " +  newFileName  + " " + newTCDir  ;
      // ">> moveAside.out";
       System.out.println("MA: " + path + "<<<");
       Runtime rn = Runtime.getRuntime();
       Process pr = rn.exec(path);

    catch (Exception e)
   
       System.out.println("----Exception in MoveAside: " + e.getMessage());
       return 1;
   
    System.out.println("----MoveAside: run successfully");

   return 0;

上面 System.out.println 的一个典型调用是:

"C:\Program Files (x86)\PERPLXDAM"\moveAside.bat C:\IronLayer\PERPLXDAM\ C:\Users\johnf\onedrive\Desktop\robin042920e.DVNC C:\Users\johnf\onedrive\Desktop \

bat文件moveAside.bat是:

::
::---setup remover bat
::
::  %1 - desktop directory name
::  %2 - transcode file name and path
::  %3 - desktop location
::

echo on

for /F "tokens=2" %%i in ('date /t') do set mydate=%%i
set mytime=%time%


 echo  %mydate%:%mytime% "==" PPLXCTL.cfg %1 "==" %2 =="C:\IronLayer\PERPLXDAM\"  == "desktop:         " + %3 >>"C:\IronLayer\PERPLXDAM\Hist.log" 

set local

set "_tdir = %1"
set "_tfiledir = %2"
 echo tfiledir: "%_tfiledir%"

move /Y "%2" "C:\IronLayer\PERPLXDAM\"

move /Y "%3PPLXCTL.cfg" "C:\IronLayer\PERPLXDAM\"

::exit

(退出被注释掉,所以在我调试时命令窗口不会消失。)

图标与 .DVNC 文件范围相关联,双击其中一个文件会触发程序。但是批处理文件并没有以这种方式运行,程序的其余部分运行良好,只是不是最终的 bat 文件。

同样,如果我从命令行执行相同的 .exe,程序会正常工作,并且 .bat 会成功运行,并且文件会从桌面复制。

【问题讨论】:

打印什么错误信息和输出? 没有错误信息,也没有打印任何内容。查看命令窗口输出时(ISSO setup install using CMD mode)。有一条消息显示命令过程已成功运行(从 cmd 提交没有返回错误)。但是没有证据表明 bat 文件运行了。如果我打开一个命令窗口并剪切并粘贴我打印出来的内容作为 rn.exe 的参数,那么 bat 文件就会成功运行。 【参考方案1】:

这里有几件事要检查:

EXE 的环境/目录可能与您以java -jar classname 运行时的环境/目录不同 - 请在使用前通过打印 dir 路径仔细检查。

如果可能,运行命令不带 cmd.exe,并删除路径上的奇怪转义。 Java 有用于所有路径操作的 File / Path 类:

String[] path = new String[] 
     new File(UserDir, "moveAside.bat").toAbsolutePath()
    , "C:\\IronLayer\\PERPLXDAM\\"
    , FilenameIn
    , TCDir
;

还要检查错误:在start()之后获取子进程退出码并检查rc == 0

int rc = pr.waitFor();
// exception if rc != 0

然后检查 STDERR 以防批处理文件失败并且未返回非零代码。如果将 Runtime.exec 的使用替换为 ProcessBuilder 并合并 STDERR->STDOUT,这样做会更容易:

ProcessBuilder pb = new ProcessBuilder(path);
pb.redirectErrorStream(true);
// See also: pb.redirectError(new File("stderr.log")));
Process pr = pb.start();

try(OutputStream os = p.getOutputStream()) 
        os.transferTo(System.out);

int rc = pr.waitFor();

【讨论】:

【参考方案2】:

您调用 Runtime.exec() 方法。该方法返回一个Process实例,在it's documentation你可以阅读

默认情况下,创建的进程没有自己的终端或控制台。它的所有标准 I/O(即 stdin、stdout、stderr)操作都将被重定向到父进程,在那里可以通过使用 getOutputStream()、getInputStream() 和 getErrorStream() 方法获得的流来访问它们。父进程使用这些流向进程提供输入并从进程中获取输出。由于部分原生平台只为标准输入输出流提供有限的缓冲区大小,未能及时写入进程的输入流或读取输出流可能会导致进程阻塞,甚至死锁。

因此,您的进程很可能是由操作系统启动的,但由于 I/O 限制而被阻止。通过阅读 STDOUT 和 STDERR 流直到您的流程完成来解决这个问题。 https://www.baeldung.com/run-shell-command-in-java

可以看到一个很好的编程模型

【讨论】:

以上是关于已安装的 Java 程序提交批处理文件但它不执行。从命令窗口执行相同的可执行文件有效的主要内容,如果未能解决你的问题,请参考以下文章

Java保存功能不会覆盖

我已经下载了猪,但它不工作

如何在 Xcode 5 上安装新的 iOS SDK?

422 无法处理的实体错误。我尝试上传 Excel 文件以导入数据,但它不工作

用一个图标执行 java 应用程序

手机java程序在安装jar文件时提示(jar文件已损坏)怎么解决