2011-09-26 96 views
2

我想通過在Linux下使用ProcessBuilder類將mp3文件解碼爲wav文件。出於某種原因,該過程不會停止,因此我必須手動取消它。ProcessBuilder不停止

有人可以給我一個提示。我認爲引用的代碼很容易重現:jstack的

import java.io.*; 

public class Test { 
public static void main(String[] args) { 
    try { 
     Process lameProcess = new ProcessBuilder("lame", "--decode", "test.mp3", "-").start(); 
     InputStream is = lameProcess.getInputStream(); 
     FileOutputStream fileOutput = new FileOutputStream("test.wav"); 
     DataOutputStream dataOutput = new DataOutputStream(fileOutput); 


     byte[] buf = new byte[32 * 1024]; 
     int nRead = 0; 
     int counter = 0; 
     while((nRead = is.read(buf)) != -1) { 
      dataOutput.write(buf, 0, buf.length); 
     } 

     is.close(); 
     fileOutput.close(); 

    } 
    catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 
} 

輸出

"main" prio=10 tid=0x0000000002588800 nid=0x247a runnable [0x00007f17e2761000] 
    java.lang.Thread.State: RUNNABLE 
    at java.io.FileInputStream.readBytes(Native Method) 
    at java.io.FileInputStream.read(FileInputStream.java:236) 
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:235) 
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:275) 
    at java.io.BufferedInputStream.read(BufferedInputStream.java:334) 
    - locked <0x00000000eb5b1660> (a java.io.BufferedInputStream) 
    at java.io.FilterInputStream.read(FilterInputStream.java:107) 
    at Test.main(Test.java:17) 
+0

不應該在'Process'對象上調用'waitFor()'方法嗎? – biziclop

+1

它掛在哪裏?使用'jstack '或'kill -3 '獲得線程轉儲。 –

+0

看起來像掛在'read()'調用中。你的外部進程是否終止? –

回答

7

你需要(通過getInputStream())地漏無論是產量和錯誤(通過getErrorStream())過程的流否則可能會阻塞。

引述Process documentation

由於某些本地平臺只提供用於標準輸入和輸出流有限緩衝區的大小,沒有及時寫輸入流或讀出的子過程的輸出流可能會導致子進程阻塞甚至死鎖。

(這既適用於錯誤和輸出流)

你可能需要將每個數據流在不同的線程漏,因爲當它沒有數據的每個可能阻塞。

+0

或者您可以使用[ProcessBuilder.redirectErrorStream()](http://download.oracle.com/javase/6/docs/api/java/lang/ProcessBuilder.html#redirectErrorStream(boolean))將流合併爲一個讓生活更輕鬆。 – Jon7

+0

+1。我的建議是使用'java.util.concurrent'產生一個新的線程,並將感興趣的'InputStream'傳遞到新的線程進行累積。您可以使用Apache IO commons在一行中完成:'IOUtils.toString(inputStream,YOUR_CONSOLE_CHARSET);' –

+1

@ Jon7 redirectErrorStream()在這種特殊情況下可能不是一個好主意 - 輸出流用作WAVE輸出並具有在那裏混入的錯誤信息會破壞WAV文件。 – prunge

3

使用LAME Java包裝器如LAMEOnJ可能會容易得多。這樣你可以避免產生流程,你可以像蹩腳的Java庫一樣進行交互。