Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
process.waitFor();
Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
process.waitFor();
जवाबों:
कई कारण हैं जो waitFor()
वापस नहीं आते हैं।
लेकिन यह आमतौर पर इस तथ्य को उबालता है कि निष्पादित कमांड नहीं छोड़ता है।
यह, फिर से, कई कारण हो सकते हैं।
एक सामान्य कारण यह है कि प्रक्रिया कुछ आउटपुट का उत्पादन करती है और आप उचित धाराओं से नहीं पढ़ते हैं। इसका मतलब यह है कि बफर के पूर्ण होते ही प्रक्रिया अवरुद्ध हो जाती है और आपकी प्रक्रिया को पढ़ने के लिए जारी रखने का इंतजार करता है। बदले में आपकी प्रक्रिया दूसरी प्रक्रिया समाप्त होने का इंतजार करती है (जो कि ऐसा नहीं होगा क्योंकि यह आपकी प्रक्रिया का इंतजार करती है, ...)। यह एक शास्त्रीय गतिरोध की स्थिति है।
आपको प्रक्रियाओं को इनपुट स्ट्रीम से लगातार पढ़ने की ज़रूरत है ताकि यह सुनिश्चित हो सके कि यह ब्लॉक नहीं होता है।
वहाँ एक अच्छा लेख है जो सभी प्रकार के नुकसानों के बारे में बताता है Runtime.exec()
और उनके आस-पास के तरीके दिखाता है, जिन्हें "जब Runtime.exec () नहीं होगा" (हाँ, लेख 2000 से है, लेकिन सामग्री अभी भी लागू होती है!)
waitFor()
नहीं लौटता है।
ऐसा प्रतीत होता है कि आप इसके खत्म होने का इंतजार करने से पहले आउटपुट नहीं पढ़ रहे हैं। यह तभी ठीक होता है जब आउटपुट बफर को नहीं भरता है। यदि ऐसा होता है, तो यह तब तक इंतजार करेगा जब तक आप आउटपुट, कैच -22 को नहीं पढ़ लेते।
शायद आपकी कुछ त्रुटियां हैं जो आप नहीं पढ़ रहे हैं। यह अनुप्रयोग को रोकने और हमेशा के लिए प्रतीक्षा करने के लिए प्रतीक्षा करेगा। इसके आस-पास एक सरल तरीका यह है कि नियमित आउटपुट में त्रुटियों को फिर से निर्देशित किया जाए।
ProcessBuilder pb = new ProcessBuilder("tasklist");
pb.redirectErrorStream(true);
Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
System.out.println("tasklist: " + line);
process.waitFor();
pb.redirectError(new File("/dev/null"));
redirectError
जावा 1.7 के बाद से ही उपलब्ध है
जावा डॉक्टर से भी:
java.lang
कक्षा प्रक्रिया
क्योंकि कुछ देशी प्लेटफ़ॉर्म केवल मानक इनपुट और आउटपुट स्ट्रीम के लिए सीमित बफर आकार प्रदान करते हैं, इनपुट स्ट्रीम को तुरंत लिखने में विफलता या उपप्रकार के आउटपुट स्ट्रीम को पढ़ने के कारण उपप्रकार ब्लॉक हो सकता है, और यहां तक कि गतिरोध भी हो सकता है।
प्रक्रिया से इनपुट स्ट्रीम (जो सबप्रोसेस के आउटपुट स्ट्रीम में पाइप) को बफ़र करने में विफल हो सकता है, जिससे सबप्रोसेस ब्लॉक हो सकता है।
इसे इस्तेमाल करे:
Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {}
process.waitFor();
DefaultExecutor executor = new DefaultExecutor(); PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(stdoutOS, stderrOS); executor.setStreamHandler(pumpStreamHandler); executor.execute(cmdLine);
जहाँ stoutOS और stderrOS BufferedOutputStream
s हैं, मैंने उचित फ़ाइलों को लिखने के लिए बनाया है।
process.close()
। लेकिन जब मैं ऊपर के रूप में सुझाए गए इनपुट स्ट्रीम को खोलता हूं और तुरंत बंद कर देता हूं - समस्या दूर हो जाती है। तो मेरे मामले में स्प्रिंग स्ट्रीम क्लोज सिग्नल का इंतजार कर रहा था। हालांकि मैं जावा 8 ऑटो बंद करने योग्य उपयोग कर रहा हूं।
मैं पिछले उत्तरों में कुछ जोड़ना चाहूंगा लेकिन चूंकि मेरे पास टिप्पणी करने के लिए रिपीट नहीं है, मैं सिर्फ एक उत्तर जोड़ूंगा। यह उन Android उपयोगकर्ताओं की ओर निर्देशित है जो जावा में प्रोग्रामिंग कर रहे हैं।
रोलिंगबॉय के पोस्ट के अनुसार, इस कोड ने लगभग मेरे लिए काम किया:
Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {}
process.waitFor();
मेरे मामले में, वेटफ़ोर () रिलीज़ नहीं हो रहा था क्योंकि मैं बिना रिटर्न वाले बयान को निष्पादित कर रहा था ("आईपी एडड्र फ्लश एथ0")। इसे ठीक करने का एक आसान तरीका यह है कि आप यह सुनिश्चित करें कि आप हमेशा अपने बयान में कुछ वापस करें। मेरे लिए, इसका मतलब है कि निम्नलिखित को निष्पादित करना: "आईपी एडड्र फ्लश एथ0 और& इको किया गया"। आप पूरे दिन बफर पढ़ सकते हैं, लेकिन अगर कभी कुछ वापस नहीं किया जाता है, तो आपका धागा कभी भी अपना इंतजार नहीं करेगा।
आशा है कि किसी की मदद करता है!
process.waitFor()
कि यह लटका है reader.readLine()
कि अगर आप कोई उत्पादन नहीं है तो यह लटका हुआ है। मैंने waitFor(long,TimeUnit)
टाइमआउट का उपयोग करने की कोशिश की अगर कुछ गलत हो गया और पता चला कि यह रीड द हंग था। जो टाइमआउट किए गए संस्करण को रीडिंग करने के लिए एक और थ्रेड की आवश्यकता होती है ...
कई संभावनाएं हैं:
stdout
।stderr
।stdin
।जैसा कि दूसरों ने उल्लेख किया है कि आपको स्टेडर और स्टडआउट का सेवन करना होगा ।
अन्य उत्तरों की तुलना में, जावा 1.7 के बाद से यह और भी आसान है। आपको स्ट्रेडर और स्टडआउट को पढ़ने के लिए खुद को थ्रेड्स बनाने की आवश्यकता नहीं है ।
बस का उपयोग करें ProcessBuilder
और या redirectOutput
तो के साथ संयोजन में विधियों का उपयोग करें ।redirectError
redirectErrorStream
String directory = "/working/dir";
File out = new File(...); // File to write stdout to
File err = new File(...); // File to write stderr to
ProcessBuilder builder = new ProcessBuilder();
builder.directory(new File(directory));
builder.command(command);
builder.redirectOutput(out); // Redirect stdout to file
if(out == err) {
builder.redirectErrorStream(true); // Combine stderr into stdout
} else {
builder.redirectError(err); // Redirect stderr to file
}
Process process = builder.start();
उसी कारण से आप inheritIO()
बाहरी ऐप कंसोल जैसे जावा कंसोल मैप करने के लिए भी उपयोग कर सकते हैं जैसे:
ProcessBuilder pb = new ProcessBuilder(appPath, arguments);
pb.directory(new File(appFile.getParent()));
pb.inheritIO();
Process process = pb.start();
int success = process.waitFor();
आपको उसी समय में आउटपुट और त्रुटि का उपभोग करने की कोशिश करनी चाहिए
private void runCMD(String CMD) throws IOException, InterruptedException {
System.out.println("Standard output: " + CMD);
Process process = Runtime.getRuntime().exec(CMD);
// Get input streams
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = "";
String newLineCharacter = System.getProperty("line.separator");
boolean isOutReady = false;
boolean isErrorReady = false;
boolean isProcessAlive = false;
boolean isErrorOut = true;
boolean isErrorError = true;
System.out.println("Read command ");
while (process.isAlive()) {
//Read the stdOut
do {
isOutReady = stdInput.ready();
//System.out.println("OUT READY " + isOutReady);
isErrorOut = true;
isErrorError = true;
if (isOutReady) {
line = stdInput.readLine();
isErrorOut = false;
System.out.println("=====================================================================================" + line + newLineCharacter);
}
isErrorReady = stdError.ready();
//System.out.println("ERROR READY " + isErrorReady);
if (isErrorReady) {
line = stdError.readLine();
isErrorError = false;
System.out.println("ERROR::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" + line + newLineCharacter);
}
isProcessAlive = process.isAlive();
//System.out.println("Process Alive " + isProcessAlive);
if (!isProcessAlive) {
System.out.println(":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Process DIE " + line + newLineCharacter);
line = null;
isErrorError = false;
process.waitFor(1000, TimeUnit.MILLISECONDS);
}
} while (line != null);
//Nothing else to read, lets pause for a bit before trying again
System.out.println("PROCESS WAIT FOR");
process.waitFor(100, TimeUnit.MILLISECONDS);
}
System.out.println("Command finished");
}
मुझे लगता है कि मैंने एक समान समस्या देखी: कुछ प्रक्रियाएं शुरू हुईं, लगता है कि वे सफलतापूर्वक चलेंगी लेकिन कभी पूरी नहीं हुईं। फ़ंक्शन प्रतीक्षाकर्ता () हमेशा इंतजार कर रहा था सिवाय अगर मैंने टास्क मैनेजर में प्रक्रिया को मार दिया।
हालाँकि, कमांड लाइन की लंबाई 127 वर्ण या उससे कम होने की स्थिति में सब कुछ ठीक रहा। यदि लंबी फ़ाइल नाम अपरिहार्य हैं, तो आप पर्यावरण चर का उपयोग करना चाह सकते हैं, जो आपको कमांड लाइन स्ट्रिंग को छोटा रखने की अनुमति दे सकता है। आप एक बैच फ़ाइल (FileWriter का उपयोग करके) उत्पन्न कर सकते हैं जिसमें आप अपने पर्यावरण चर को उस प्रोग्राम को कॉल करने से पहले सेट करते हैं जिसे आप वास्तव में चलाना चाहते हैं। इस तरह के एक बैच की सामग्री की तरह लग सकता है:
set INPUTFILE="C:\Directory 0\Subdirectory 1\AnyFileName"
set OUTPUTFILE="C:\Directory 2\Subdirectory 3\AnotherFileName"
set MYPROG="C:\Directory 4\Subdirectory 5\ExecutableFileName.exe"
%MYPROG% %INPUTFILE% %OUTPUTFILE%
अंतिम चरण रनटाइम का उपयोग करके इस बैच फ़ाइल को चला रहा है।
यहाँ एक विधि है जो मेरे लिए काम करती है। नोट: इस पद्धति के भीतर कुछ कोड है जो आपके लिए लागू नहीं हो सकता है, इसलिए इसे आज़माएं और अनदेखा करें। उदाहरण के लिए "logStandardOut (...), git-bash, आदि"।
private String exeShellCommand(String doCommand, String inDir, boolean ignoreErrors) {
logStandardOut("> %s", doCommand);
ProcessBuilder builder = new ProcessBuilder();
StringBuilder stdOut = new StringBuilder();
StringBuilder stdErr = new StringBuilder();
boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
if (isWindows) {
String gitBashPathForWindows = "C:\\Program Files\\Git\\bin\\bash";
builder.command(gitBashPathForWindows, "-c", doCommand);
} else {
builder.command("bash", "-c", doCommand);
}
//Do we need to change dirs?
if (inDir != null) {
builder.directory(new File(inDir));
}
//Execute it
Process process = null;
BufferedReader brStdOut;
BufferedReader brStdErr;
try {
//Start the command line process
process = builder.start();
//This hangs on a large file
// /programming/5483830/process-waitfor-never-returns
//exitCode = process.waitFor();
//This will have both StdIn and StdErr
brStdOut = new BufferedReader(new InputStreamReader(process.getInputStream()));
brStdErr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
//Get the process output
String line = null;
String newLineCharacter = System.getProperty("line.separator");
while (process.isAlive()) {
//Read the stdOut
while ((line = brStdOut.readLine()) != null) {
stdOut.append(line + newLineCharacter);
}
//Read the stdErr
while ((line = brStdErr.readLine()) != null) {
stdErr.append(line + newLineCharacter);
}
//Nothing else to read, lets pause for a bit before trying again
process.waitFor(100, TimeUnit.MILLISECONDS);
}
//Read anything left, after the process exited
while ((line = brStdOut.readLine()) != null) {
stdOut.append(line + newLineCharacter);
}
//Read anything left, after the process exited
while ((line = brStdErr.readLine()) != null) {
stdErr.append(line + newLineCharacter);
}
//cleanup
if (brStdOut != null) {
brStdOut.close();
}
if (brStdErr != null) {
brStdOut.close();
}
//Log non-zero exit values
if (!ignoreErrors && process.exitValue() != 0) {
String exMsg = String.format("%s%nprocess.exitValue=%s", stdErr, process.exitValue());
throw new ExecuteCommandException(exMsg);
}
} catch (ExecuteCommandException e) {
throw e;
} catch (Exception e) {
throw new ExecuteCommandException(stdErr.toString(), e);
} finally {
//Log the results
logStandardOut(stdOut.toString());
logStandardError(stdErr.toString());
}
return stdOut.toString();
}
समय के साथ प्रतीक्षा से बचने के साथ संयुक्त धारा के अतुल्यकालिक पढ़ने से समस्या हल हो जाएगी।
आप इसे यहाँ समझाने वाला एक पृष्ठ पा सकते हैं http://simplebasics.net/.net/process-waitforexit-with-a-timeout-will-not-be-able-to-collect-the-output-message/