import java
io
*;
public class CommandWrapper
{
Process process;
Thread in;
Thread out;
public CommandWrapper(Process process)
{
this
process = process;
final InputStream inputStream =
process
getInputStream();
//final BufferedReader
r=new BufferedReader
(new InputStreamReader(inputStream));
final byte[] buffer = new byte[
];
out = new Thread()
{
//String line;
int lineNumber=
;
public void run()
{
try {
while (true)
{
int count = inputStream
read(buffer);
System
out
println
(lineNumber+
:
+new String
(buffer
count
));
//line=r
readLine();
//System
out
println
(lineNumber+
:
+line);
lineNumber++;
}
}
catch (Exception e)
{
}
}
};
final BufferedReader reader =
new BufferedReader
(new InputStreamReader(System
in));
final OutputStream
outputStream = process
getOutputStream();
in = new Thread()
{
String line;
public void run()
{
try
{
while (true)
{
outputStream
write(
(reader
readLine()+
\n
)
getBytes());
outputStream
flush();
}
}
catch (Exception e)
{
}
}
};
}
public void startIn()
{
in
start();
}
public void startOut()
{
out
start();
}
public void interruptIn()
{
in
interrupt();
}
public void interruptOut()
{
out
interrupt();
}
public static void main
(String[] args)
{
try
{
CommandWrapper command
= new CommandWrapper
(Runtime
getRuntime()
exec(
native
ascii
));
command
startIn();
command
startOut();
}
catch (Exception e)
{
e
printStackTrace();
}
}
}
我以native
ascii為范例程序和網友給我的那個程序做了對比
發現如下幾個在處理這個問題時需要注意的地方
由於不知道目標程序的輸入輸出順序
因此只能建立兩個單獨的線程分別處理輸入和輸出
這樣輸入和輸出就不會阻塞了
但是有些目標程序要求有特定的輸入輸出順序
而經過這個類封裝的結果是在任何狀態下都可以輸入
程序的任何輸出也會被馬上反映出來
這是構造通用類的第一個問題
不能直接使用I/O重定向
在最開始的時候我是考慮直接使用I/O重定向的
但是實際的情況是Process的I/O的定義剛好和我的預想相反
我們從Process取得的InputStream實際上是它的輸出
而取得的OutputStream是它的輸入
這樣就無法進行I/O重定向了
必須我們進行編碼來讀取程序的輸出和寫入控制台的輸入
(這裡的I/O重定向是指想將它的I/O直接重定向到系統的I/O)
寫入控制台的輸入
outputStream
write(
(reader
readLine()+
\n
)
getBytes());
outputStream
flush();
這裡有兩個問題值得注意
第一個是我們在控制台輸入一行數據以後按下回車
那麼語句reader
readLine()可以正確的得到你的輸入
為什麼要加那個換行符呢?這是在測試的時候發現的問題
在以native
ascii作為例子的時候發現不加這個的話它不能得到控制台的輸入
但是我在替那位網友解決的問題的時候他的程序則沒有這個問題
因此猜想可能是因為有的程序要求讀取的一整行的數據(例如native
ascii)
而大部分的命令行程序在編碼的時候讀取的是整數這樣的值或者其他類型的值
他們是以空格或者其他的字符分隔的
因此就不需要那個額外的換行符(例如那位網友的程序讀取的是一元二次方程的三個系數)
另外一個問題就是flush方法的使用
在最開始的時候沒有想到要這樣刷新進去
無論是否加換行符外部程序都無法讀取寫入的輸入
後來才想到要調用一下這個方法
這個也是在我們輸出的時候應該注意的一個問題
有些需要馬上反應出來的輸出一般都在寫入以後要調用它
否則輸出/輸入不能馬上反應出來
對於程序的輸出
最開始我是構造的一個BufferedReader想以行為單位輸出
對於那位網友的程序
結果證明不是很好用
但是以native
ascii作為例子運行又沒有問題
這個估計和外部程序的代碼也有關系
如果外部程序沒有輸出換行符可能使用BufferedReader就會有問題
但是通過直接讀取輸出就沒有問題了
另外需要注意的就是
System
out
println
(lineNumber+
:
+new String
(buffer
count
));
中嚴格來說應該是
System
out
println
(lineNumber+
:
+new String
(buffer
count));
之所以減一是因為讀取輸入的時候人為的多加了一個換行符
如果這個地方不減一就會多輸出一個空行
基於以上的種種原因
要構造一個執行外部程序的包裝器類不太好辦
特別是文章中提到的幾個問題
有時間和興趣的朋友可以做一下測試
看看以上的問題和猜測是否正確
另外附上一段源代碼
是一個fortran的程序
implicit none
real a
b
c
real d
real root
root
print*
請輸入一元二次方程
的系數a
b
c:
read(*
*) a
b
c
d=b**
*a*c
if(d>=
) then
root
=(
b+sqrt(d))/(
*a)
root
=(
b
sqrt(d))/(
*a)
print*
root
=
root
print*
root
=
root
else
print*
一元二次方程沒有實根!
end if
pause
end
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19704.html