web-dev-qa-db-ja.com

Java getRuntime()。exec()を取得して、引数を指定してコマンドラインプログラムを実行する方法は?

コマンドラインを使用してプログラム「tesseract」のインスタンスを実行するためにRuntime.getRuntime().exec()メソッドを使用するJavaプログラムを記述しようとしています。

一部の背景として、Tesseractは無料のオープンソースプログラムで、写真にOCR(光学式文字認識)を実行するために使用されます。画像ファイルを取り込んでテキスト文書を出力します。これは、このコマンドを使用して実行するコマンドラインプログラムです。

(コマンドプロンプトシェル内から)

_tesseract imageFilePath outFilePath [optional arguments] 
_

例:

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

最初の引数はtesseractプログラムを呼び出し、2番目は画像ファイルへの絶対パス、最後の引数は出力ファイルのパスと名前です。 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\""を渡そうとしても、同じエラーが発生しました。

getRuntime()。exec内での引用の使用 によると、引用符をエスケープしようとしたことが問題であると考えたため、文字列配列を渡しました。しかし、まだ_Exited with error code 1_を取得しています。

Java Runtime.getRuntime().exec()コマンドを使用してコマンドラインプログラムを実行することは可能ですか?


[〜#〜] edit [〜#〜]:問題はまだ発生しています

Evgeniy DorofeevとNandkumar Tekaleが以下に提案するのと同じ推論に沿って「cmd/c」の考え方を使用しないようにしてみました。ただし、別の種類のエラーが発生します。

_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
_

多分これはより多くの情報を提供しますか?何がこの問題を引き起こしているのか本当に知りたいです。また、エスケープされた引用を引数に追加してもしなくても問題は同じです。


EDIT 2:気まぐれにtesseract実行可能ファイルへの絶対パスを指定し、_cmd /c_を使用しないのは魅力のように機能しました。問題はRuntime.getRuntime().exec()が環境変数を呼び出せないことでしょうか?

10
Samuel

STDERRをキャプチャしていないため、エラーが発生しても、STDOUT(キャプチャしている)からエラーを受け取りません。試してください:

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

tesseractは外部コマンドなので、cmdと一緒に使用する必要はありません。環境変数にtesseractを追加します。次のように直接コマンドを使用します。

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

存在ステータス1は、機能が正しくないことを意味します。参照 プロセスの終了ステータス

1

再コンパイルして展開する必要がない別の回避策は、古いDOSスタイルのパスを使用することです。たとえば、C:\Program FilesC:\Progra~1になります。もちろん、これは、設定ファイルまたはDBやレジストリなどからパスを読み取る場合にのみ役立ちます。

0
user1382115

別の回避策は、/ usr/local/Cellar/tesseract/3.02.02/bin/tesseractのようなファイルの完全なインストールパスを与えることです。

0
Raj Pandiri