【问题标题】:How to get java getRuntime().exec() to run a command-line program with arguments?如何让 java getRuntime().exec() 运行带参数的命令行程序?
【发布时间】:2012-11-08 04:07:54
【问题描述】:

我一直在尝试编写一个 java 程序,它使用Runtime.getRuntime().exec() 方法来使用命令行运行程序“tesseract”的实例。

一些背景知识,Tesseract 是一个免费的开源程序,用于对图片进行 OCR(光学字符识别)。它接收一个图片文件并输出一个文本文件。它是一个命令行程序,使用这个命令来运行

(在命令提示符 shell 中)

tesseract imageFilePath outFilePath [optional arguments] 

示例:

tesseract "C:\Program Files (x86)\Tesseract-OCR\doc\eurotext.tif" "C:\Users\Dreadnought\Documents\TestingFolder\out"

第一个参数调用 tesseract 程序,第二个是图像文件的绝对路径,最后一个参数是输出文件的路径和名称。 Tesseract 只需要输出文件的名称,不需要扩展名。

在命令提示符下工作,这是完美的。但是,我想从 java 程序中运行它并且遇到了一些错误。

我发现此代码作为起点非常有用

public class Main
{
   public static void main(String args[])
   {
      try
      {
         Runtime rt = Runtime.getRuntime();
         String cmdString = "cmd /c dir";

         System.out.println(cmdString);
         Process pr = rt.exec(cmdString);

         BufferedReader input = new BufferedReader(new InputStreamReader(
                                                   pr.getInputStream()));

         String line = null;

         while ((line = input.readLine()) != null)
         {
            System.out.println(line);
         }

         int exitVal = pr.waitFor();
         System.out.println("Exited with error code " + exitVal);

      }
      catch (Exception e)
      {
         System.out.println(e.toString());
         e.printStackTrace();
      }
   }
}

它打印出 dir 命令的结果。但是当我这样修改它时

public class Main
{
   public static void main(String args[])
   {
      try
      {
         Runtime rt = Runtime.getRuntime();
         String imageFilePath = "\"C:\\Program Files (x86)\\Tesseract-OCR\\doc\\eurotext.tif\"";
         String outputFilePath = "\"C:\\Users\\Dreadnought\\Documents\\TestingFolder\\eurotext-example\"";
         String[] commands = {"cmd", "/c", "tesseract", imageFilePath, outputFilePath };

         Process pr = rt.exec(commands);

         BufferedReader input = new BufferedReader(new InputStreamReader(
               pr.getInputStream()));

         String line = null;

         while ((line = input.readLine()) != null)
         {
            System.out.println(line);
         }

         int exitVal = pr.waitFor();
         System.out.println("Exited with error code " + exitVal);
      }
      catch (Exception e)
      {
         System.out.println(e.toString());
         e.printStackTrace();
      }
   }
}

它唯一输出的是Exited with error code 1。如果进程以错误结束,这是预期的输出。

我什至尝试过传递"cmd /c tesseract \"C:\\Program Files (x86)\\Tesseract-OCR\\doc\\eurotext.tif\" \"C:\\Users\\Dreadnought\\Documents\\TestingFolder\\eurotext-example\"",但我最终遇到了同样的错误。

根据Using Quotes within getRuntime().exec,我认为问题在于我试图转义引号,所以这就是我传入一个字符串数组的原因。但我仍然收到Exited with error code 1

是否可以使用 java Runtime.getRuntime().exec() 命令执行命令行程序?


编辑:问题仍然存在

我尝试过不使用“cmd /c”的思路,就像 Evgeniy Dorofeev 和 Nandkumar Tekale 下面建议的那样。但是,我得到了另一种错误:

java.io.IOException: Cannot run program "tesseract": CreateProcess error=2, The system cannot find the file specified
java.io.IOException: Cannot run program "tesseract": CreateProcess error=2, The system  cannot find the file specified
    at java.lang.ProcessBuilder.start(Unknown Source)
    at java.lang.Runtime.exec(Unknown Source)
    at java.lang.Runtime.exec(Unknown Source)
    at Main.main(Main.java:15)
Caused by: java.io.IOException: CreateProcess error=2, The system cannot find the file specified
    at java.lang.ProcessImpl.create(Native Method)
    at java.lang.ProcessImpl.<init>(Unknown Source)
    at java.lang.ProcessImpl.start(Unknown Source)
... 4 more

也许这会提供更多信息?我真的很好奇是什么导致了这个问题。无论我是否将转义引号添加到我的论点中,问题都是相同的。


编辑 2:一时兴起,我提供了 tesseract 可执行文件的绝对路径,而不使用 cmd /c 就像一个魅力。我想问题是Runtime.getRuntime().exec()可以不调用环境变量吗?

【问题讨论】:

  • 我不确定,但C:\\Program Files (x86) 可能存在路径中包含空格的问题。
  • 我认为这是问题的根源,这就是我尝试使用引号的原因,但如果这些不适用于 exec,您对我如何使这项工作有建议吗?
  • 您将一个数组传递给rt.exec()。不要在论点的开头和结尾加上引号。这是关于如何拆分参数的 shell 信息,但您已经这样做了。
  • 如果我不使用引号,那么我怎样才能让C:\\Program Files (x86) 保持在一起?但是,我已经尝试不带引号但仍然无法正常工作。
  • 是的,我在没有 cmd /c 的情况下使用它

标签: java process exec runtime.exec


【解决方案1】:

您没有捕获 STDERR,因此当发生错误时,您不会从 STDOUT(您正在捕获的)接收它们。试试:

BufferedReader input = new BufferedReader(new InputStreamReader(
               pr.getErrorStream()));

【讨论】:

    【解决方案2】:

    tesseract 是外部命令,因此您不需要将它与cmd 一起使用。将tesseract 添加到环境变量中。使用直接命令:

    String[] commands = {"tesseract", imageFilePath, outputFilePath };
    

    存在状态 1 表示功能不正确。见process exit status

    【讨论】:

    • 你检查过直接在cmd提示符下运行吗?
    【解决方案3】:

    另一种无需重新编译和部署的解决方法是使用旧的 DOS 样式路径,例如 C:\Program Files 将是 C:\Progra~1。当然,这只有在您从配置文件或数据库和注册表等读取路径时才会有所帮助。

    【讨论】:

      【解决方案4】:

      另一种解决方法是提供文件的完整安装路径,例如 /usr/local/Cellar/tesseract/3.02.02/bin/tesseract"

      【讨论】:

        猜你喜欢
        • 2017-11-17
        • 1970-01-01
        • 1970-01-01
        • 2012-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多