2011-07-18 11 views
3

Javaプログラムからbashスクリプトを実行し、データの断片を取り込み、操作して分割します。(Java)変更されたディレクトリ(bashスクリプト経由)はfolder.listfilesに反映されていません

bashスクリプトが動作するかどうかは問題ではありません。ディレクトリ内の分割ファイルを確認できます。

その後

try 
    { 
     Process proc = Runtime.getRuntime().exec("bash " + SCRIPT_DIR + "/" + SPLIT_SCRIPT_NAME + " " + args[_MESSAGES_PER_UPLOAD_] + " " + args[_MAXIMUM_MESSAGES_PER_FEED_] + " " + (60000*Integer.parseInt(args[_DURATION_BEFORE_EACH_UPLOAD_IN_MINUTES_])/Integer.parseInt(args[_DURATION_OF_EACH_FEED_IN_MILLISECONDS_]))); 
     proc.waitFor(); 
    } 
    catch(IOException e) { error(e); } 

    String fileNames; 
    File folder = new File(DATA_DIR); 

    File[] filesToUpload = folder.listFiles(); 

    for (int i = 0; i < filesToUpload.length; ++i) 
     if (filesToUpload[i].isFile()) 
     { 
      fileNames = filesToUpload[i].getName(); 
      System.out.println(fileNames); 
     } 

が大型ファイルを印刷します、ではない...

$ lsのデータ/

dataChunk_00000 dataChunk_00001 /元のファイルは、データの "大型ファイル" だったと言います dataChunk_00002 dataChunk_00003 dataChunk_00004 dataChunk_00005 dataChunk_00006 dataChunk_00007 dataChunk_00008 dataChunk_00009 dataChunk_00010 dataChunk_00011 dataChunk_00012 dataChunk_00013 dataChunk_00014 dataChunk_00015 dataChunk_00016 dataChunk_00017 dataChunk_00018 dataChunk_00019 dataChunk_00020 dataChunk_00021 dataChunk_00022 dataChunk_00023 dataChunk_00024 dataChunk_ 00025 dataChunk_00026 dataChunk_00027

私はこれがコンパイラの最適化か何かを推測しています。

編集:誰かが私になぜproc.waitFor()がうまくいかないか、そして/またはこれを解決するためのより良い方法を説明できたら、私はそれを高く評価します。

+0

bashスクリプトのコンテンツを共有できますか?または、少なくともそれが何をしているのかを説明してください。 –

+0

さて、ここでやっているのと同じように、 '.exec(String)'の代わりに 'Runtime.exec(String [])'を使うべきです。 'Runtime.exec()'はシェルやパーサーではなく、クォートやエスケープを尊重しません。 'exec(String)'がスペースを盲目的に分割するため、すべての引数を単一の文字列で指定すると、引数の予期しない扱いにつながることがあります。 –

答えて

3

この問題は、コンパイラの最適化やそのようなものではありません。

スクリプトの前に「bash」を付けてスクリプトを呼び出すためです。これによりプロセスがforkされ、bashコマンドはすぐに成功しますが、スクリプトはバックグラウンドで実行され続けて終了します。

proc.waitFor()は何も待たずに、ファイルが分割される前にJavaプログラムの残りの部分が実行されます。

+0

私は参照してください。 Thread.sleep()を使用する以外の方法がありますか? – Ryan

+0

あなたは "bash"を取り除き、スクリプトを直接実行させることができます(新しいプロセスを生成しません)。 – Kal

+0

それは私を与える! - プログラム "スクリプト/ splitAndEnumerate.sh"を実行できません:java.io.IOException:エラー= 13、許可が拒否されました – Ryan

1

私はあなたのbashスクリプトが独自のプロセス/スレッドから非同期にアクションを実行していると推測しています。これは、作業が完了する前にスクリプトの実行が終了したことを意味します。これはまだwaitFor()チェックに合格し、コードの実行を続けます。

編集: カルの答えはこれをより明確に説明し、最初に投稿されました。問題は、スクリプトを実行するためにbashコマンドを使用することです。

0

あなたの議論がすべてあなたのスクリプトに渡されていないと思われます。

すべての引数をArrayListインスタンスに入れ、そのインスタンスをProcessBuilderに渡してから、waitForを呼び出したprocを返すbuilderインスタンスのstartメソッドを呼び出します。

ここではサンプルScalaのコードが;-)あなたが本当に興味があるなら、私は、Javaに(私ができるポートに何を意味するかを示すためにです:REPLで

import java.lang.{ Process => JProcess, ProcessBuilder => JProcessBuilder } 
import java.util.{ArrayList => JArrayList, List => JList, Map => JMap} 
import java.io.{InputStreamReader, BufferedReader} 

def call(args: String*) = { 
    val command: JList[String] = new JArrayList[String]() 

    args.foreach {arg => 
     command.add(arg) 
    } 

    //log.debug("argument list: %s", command.toString) 

    val builder = new JProcessBuilder(command) 

    val proc: JProcess = builder.start() 
    proc.waitFor() 

    val read = new BufferedReader(new InputStreamReader(proc.getInputStream())); 

    val sb: StringBuffer = new StringBuffer() 
    while(read.ready()) { 
     sb.append(read.readLine) 
    } 

    // sb now has the output of the called process... 

    val exitValue: Int = proc.exitValue 

    // http://stuffthathappens.com/blog/2007/11/28/crash-boom-too-many-open-files/ 
    read.close 
    proc.destroy 

    (exitValue, sb.toString) // return it 
} 

例コール:

scala> call("date") 
res156: (Int, java.lang.String) = (0,Mon 18 Jul 2011 22:29:58 BST) 
2

あなたはjavaでディレクトリを変更することはできません。 "シミュレート"したい場合は、プロパティ "user.dir"を設定するだけです。

0

このプログラムで間違った仮定の数があります。

  1. あなたがするたびに「幹部」あなたはなど、独自の環境、現在のディレクトリと、カレントディレクトリのすべての変更を新しいプロセスをforkそのプロセスのローカルなので、親プロセス(あなたのJavaプロセス)には影響しません。つまり、サブプロセスのコマンドを使用してアプリケーションの現在のパスを変更する方法はありません。Java APIはありません。本当に必要な場合は、ネイティブコールを使用する必要があります。
  2. Unix上の 'cd'コマンドは実際のコマンドです。Windowsとは異なり、シェルを実行するためにシェルは必要ありません。
  3. プロセスをフォークするときは、stdoutとstderrをなくすか、OSバッファがいっぱいになったときにブロックされることを確認する必要があります(次を参照)。
  4. Process.waitFor()が機能します。常に。

問題を解決するには、File APIを注意深く読んで、可能な限り絶対パスで作業することをお勧めします。 'カレントディレクトリ'は、シェルに入っているときには非常に便利ですが、アプリケーションにとっては混乱を招くので、絶対パスで解決する方が早いほど良いでしょう。

関連する問題