2011-09-26 98 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库一样进行交互。