2013-02-19 5 views
1

자바에서 파일 변환기를위한 약간의 GUI를 프로그래밍 중입니다. 파일 변환기는 현재 진행률을 stdout에 씁니다. 다음과 같습니다다른 프로세스 읽기 '** unbuffered ** 출력 스트림

Flow_1.wav: 28% complete, ratio=0,447

내가 진행률 표시 줄이를 설명하고 싶었다, 그래서 나는이 같은 표준 출력 과정 '읽고 있어요 :

ProcessBuilder builder = new ProcessBuilder("..."); 
builder.redirectErrorStream(true); 
Process proc = builder.start(); 
InputStream stream = proc.getInputStream(); 
byte[] b = new byte[32]; 
int length; 
while (true) { 
    length = stream.read(b); 
    if (length < 0) break; 
    // processing data 
} 

이제 문제를 관계없이 바이트 그 배열 크기를 선택하면 스트림이 4KB 청크로 읽혀집니다. 그래서 내 코드는 length = stream.read(b);까지 실행되고 나서 꽤 오랫동안 블록됩니다. 프로세스가 4KB의 출력 데이터를 생성하면 내 프로그램은이 청크를 가져 와서 32 바이트 슬라이스로 처리합니다. 그리고 나서 다시 다음 4KB를 기다립니다.

BufferedInputStream stream = new BufferedInputStream(proc.getInputStream(), 32); 

또는이 :

나는이 같은 작은 버퍼를 사용하기 위해 자바를 강제로 시도

BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()), 32); 

을하지만도 아무것도 변경되었습니다.

은 그 때 나는 발견이 : 그것은 Process 클래스는 파이프 프로세스가 '파일에 표준 출력 방식으로 구현되는 것 같다 Process source

(라인 87의 주위에). 그래서 proc.getInputStream();이 실제로하는 일은 스트림을 파일로 반환하는 것입니다. 그리고이 파일은 4KB 버퍼로 작성된 것 같습니다.

누군가 이러한 상황에 대한 대안을 알고 있습니까? 나는 그 과정의 결과를 즉시 얻고 싶다.

편집은 : 이안 로버츠에 의해 제안이 스트림은 BufferedInputStream에 싸여 것 같지 않기 때문에, 나는 또한, 파이프로 표준 에러 스트림에 컨버터의 출력을 시도했다. 여전히 4k 덩어리.

또 다른 흥미로운 사실은 : 실제로 정확히 4096 바이트를 얻지는 못했지만 약 5 개 더 많습니다. FileInputStream 자체가 원래 버퍼링 된 것 같습니다. 이 과정의 표준 출력 스트림에 연결된 코드를 보면

+2

문제가 변경되지는 않지만 Java는 데이터를 파일로 스트리밍하지 않습니다.파일 디스크립터는 운영 체제가 프로세스 입력/출력 스트림을 설명하는 방법입니다. _real_ 파일과 반드시 ​​상관 관계가있는 것은 아닙니다. – jtahlborn

+0

보통 stdout은이 프로세스를 쓰는 프로세스에 의해 이미 버퍼링되어 있기 때문에 다른 프로세스를 변경할 수없는 경우에는 아무런 기회가 없습니다. 이 프로세스는 버퍼링을 해제하거나 flush()를 더 자주 호출해야합니다. –

+0

@PhilippWendler : 컨버터의 표준 출력은 4KB (터미널에서 실행할 때)보다 더 자주 플러시됩니다. stdout이 콘솔로 보내지지 않을 때 \ n의 자동 플러시가 꺼져 있다고 생각합니까? –

답변

2

BufferedInputStream에 싸여 도착하지만 표준 오류가 버퍼링 남아있다. 그래서 하나의 가능성은 stderr로 컨버터의 표준 출력을 보내는 직접적 컨버터,하지만 쉘 스크립트 (또는 Windows에 해당 Windows에서 인 경우)을 실행하는 수 있습니다

ProcessBuilder builder = new ProcessBuilder("/bin/sh", "-c", 
    "exec /path/to/converter args 1>&2"); 

하지redirectErrorStream를 수행하고, proc.getInputStream() 대신 proc.getErrorStream()에서 읽습니다.

컨버터가 진행 상황보고를 위해 이미 stderr를 사용하고있는 경우에는 스크립트 비트가 필요하지 않은 경우 redirectErrorStream()을 끕니다. 변환기 프로그램이 stdout과 stderr에 모두 쓰는 경우에는 stdout을 소비하기 위해 두 번째 스레드를 생성해야합니다 (스크립트 접근법은 모든 것을 stderr로 전송하여이 문제를 해결합니다).

+0

그건 작동하지 않았다. 여전히 4k 덩어리. 어쨌든 닌자 접근에 감사드립니다. ;) –