从我们的 Java 程序执行 Java 程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/502494/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Execute a Java program from our Java program
提问by Arun
I used
我用了
Runtime.getRuntime().exec("_____")
but it throws a IOException
as below:
但它抛出IOException
如下:
java.io.IOException: CreateProcess: c:/ error=5
at java.lang.Win32Process.create(Native Method)
at java.lang.Win32Process.<init>(Win32Process.java:63)
at java.lang.Runtime.execInternal(Native Method
I don't know whether I have the problem with specifying the path or something else. Can anyone please help me with the code.
我不知道我是否在指定路径或其他方面有问题。任何人都可以帮我写代码。
回答by jdh80
How about just calling the main from your java program?
从你的java程序调用main怎么样?
Test.main(null);
测试.main(null);
This worked fine for me
这对我来说很好用
回答by Mark Davidson
Is there any reason you can't just call it directly in your Java code?
有什么理由不能直接在 Java 代码中调用它吗?
If there is a reason I've not tried it for executing a Java Program but you could try Jakarta Commons Execworks well for executing most programs.
如果有什么原因我没有尝试过它来执行 Java 程序,但您可以尝试Jakarta Commons Exec可以很好地执行大多数程序。
回答by kgiannakakis
回答by Ray Hidayat
I can't remember the exact code that I used to get this to work, but you have to pass "java.exe" (or the equivalent) as the executable, and then the class or jar to run as the parameter, with the correct working directory. So it's not as simple as just calling one method.
我不记得我用来让它工作的确切代码,但你必须将“java.exe”(或等效的)作为可执行文件传递,然后将类或 jar 作为参数运行,使用正确的工作目录。所以它不是仅仅调用一个方法那么简单。
回答by Mark
You're trying to execute "C:/". You'll want to execute something like:
您正在尝试执行“C:/”。您需要执行以下操作:
"javaw.exe d:\\somejavaprogram\\program.jar"
"javaw.exe d:\\somejavaprogram\\program.jar"
Notice the path separators.
注意路径分隔符。
I'm assuming this is for an ad-hoc project, rather than something large. However, for best practice running external programs from code:
我假设这是一个临时项目,而不是大型项目。但是,对于从代码运行外部程序的最佳实践:
- Don't hardcode the executable location, unless you're certain it will never change
- Look up directories like %windir% using System.getenv
- Don't assume programs like javaw.exe are in the search path: check them first, or allow the user to specify a location
- Make sure you're taking spaces into account:
"cmd /c start " + myProg
will not work if myProg is"my program.jar"
.
- 不要对可执行位置进行硬编码,除非您确定它永远不会改变
- 使用 System.getenv 查找 %windir% 等目录
- 不要假设像 javaw.exe 这样的程序在搜索路径中:首先检查它们,或者允许用户指定一个位置
- 确保您将空格考虑在内:
"cmd /c start " + myProg
如果 myProg 是"my program.jar"
.
回答by PhiLho
I had to do this recently.
Here is how I did it, picking up only the relevant parts:
我最近不得不这样做。
这是我是如何做到的,只挑选相关部分:
private static final String[] straJavaArgs =
{
"?i/j2re/bin/java",
"-ms64m",
"-mx64m",
"-Djava.ext.dirs=?i/lib;?i/jar/lib;?i/jar"
};
// ...
// AppDesc appToRun;
List<String> params = new ArrayList<String>();
// Java exe and parameters
params.addAll(ExpandStrings(straJavaArgs));
// Common VM arguments
params.addAll(Arrays.asList(AppDesc.GetCommonVMArgs()));
// Specific VM arguments
params.addAll(ExpandStrings(appToRun.GetVMArgs()));
// The program to run
params.add(appToRun.GetClass());
// Its arguments
params.addAll(ExpandStrings(appToRun.GetProgramArgs()));
// The common arguments
params.addAll(ExpandStrings(AppDesc.GetCommonProgramArgs()));
ProcessBuilder processBuilder = new ProcessBuilder(params);
process = processBuilder.start();
return CaptureProcessOutput(); // Uses a StreamGobbler class
protected ArrayList<String> ExpandStrings(String[] stra)
{
ArrayList<String> alResult = new ArrayList<String>();
for (int i = 0; i < stra.length; i++)
{
// Super flexible, eh? Ad hoc for the current task, at least...
alResult.add(stra[i]
.replaceAll("\?i", strInstallDir)
.replaceAll("\?c", strConfigDir)
);
}
return alResult;
}
public enum AppDesc
{
// Enumerate the applications to run, with their parameters
}
Incomplete, if you need more details, just ask.
不完整,如果您需要更多详细信息,请询问。
回答by McDowell
java.io.IOException: CreateProcess: c:/ error=5
at java.lang.Win32Process.create(Native Method)
at java.lang.Win32Process.<init>(Win32Process.java:63)
at java.lang.Runtime.execInternal(Native Method)
If I recall correctly, error code 5 means access denied. This could be because your path is incorrect (trying to execute "c:/") or you are bumping against your OS security (in which case, look at the permissions).
如果我没记错的话,错误代码 5 表示访问被拒绝。这可能是因为您的路径不正确(尝试执行“c:/”)或者您违反了操作系统安全性(在这种情况下,请查看权限)。
If you are having trouble locating the Java executable, you can usually find it using system properties:
如果您在定位 Java 可执行文件时遇到问题,通常可以使用系统属性找到它:
public class LaunchJre {
private static boolean isWindows() {
String os = System.getProperty("os.name");
if (os == null) {
throw new IllegalStateException("os.name");
}
os = os.toLowerCase();
return os.startsWith("windows");
}
public static File getJreExecutable() throws FileNotFoundException {
String jreDirectory = System.getProperty("java.home");
if (jreDirectory == null) {
throw new IllegalStateException("java.home");
}
File exe;
if (isWindows()) {
exe = new File(jreDirectory, "bin/java.exe");
} else {
exe = new File(jreDirectory, "bin/java");
}
if (!exe.isFile()) {
throw new FileNotFoundException(exe.toString());
}
return exe;
}
public static int launch(List<String> cmdarray) throws IOException,
InterruptedException {
byte[] buffer = new byte[1024];
ProcessBuilder processBuilder = new ProcessBuilder(cmdarray);
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
InputStream in = process.getInputStream();
while (true) {
int r = in.read(buffer);
if (r <= 0) {
break;
}
System.out.write(buffer, 0, r);
}
return process.waitFor();
}
public static void main(String[] args) {
try {
Runtime.getRuntime().exec("c:/");
List<String> cmdarray = new ArrayList<String>();
cmdarray.add(getJreExecutable().toString());
cmdarray.add("-version");
int retValue = launch(cmdarray);
if (retValue != 0) {
System.err.println("Error code " + retValue);
}
System.out.println("OK");
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(Tested Windows XP, Sun JRE 1.6; Ubuntu 8.04, OpenJDK JRE 1.6)
(已测试 Windows XP、Sun JRE 1.6;Ubuntu 8.04、OpenJDK JRE 1.6)
This is the equivalent of running:
这相当于运行:
java -version
You may also want to look at the "java.library.path" system property (and "path.separator") when trying to locate the executable.
尝试定位可执行文件时,您可能还想查看“java.library.path”系统属性(和“path.separator”)。
回答by Stroboskop
You can either launch another JVM (as described in detail in other answers). But that is not a solution i would prefer.
您可以启动另一个 JVM(如其他答案中所述)。但这不是我更喜欢的解决方案。
Reasons are:
原因是:
- calling a native program from java is "dirty" (and sometimes crashes your own VM)
- you need to know the path to the external JVM (modern JVMs don't set JAVA_HOME anymore)
- you have no control on the other program
- 从 Java 调用本机程序是“脏的”(有时会导致您自己的 VM 崩溃)
- 您需要知道外部 JVM 的路径(现代 JVM 不再设置 JAVA_HOME)
- 您无法控制其他程序
Main reason to do it anyway is, that the other application has no control over your part of the program either. And more importantly there's no trouble with unresponsive system threads like the AWT-Thread if the other application doesn't know its threading 101.
无论如何这样做的主要原因是,另一个应用程序也无法控制您的程序部分。更重要的是,如果其他应用程序不知道它的线程 101,那么像 AWT-Thread 这样的无响应系统线程也没有问题。
But! You can achieve more control and similar behaviour by using an elementary plugin technique. I.e. just call "a known interface method" the other application has to implement. (in this case the "main" method).
但!您可以通过使用基本插件技术实现更多控制和类似行为。即只需调用另一个应用程序必须实现的“已知接口方法”。(在本例中为“主要”方法)。
Only it's not quite as easy as it sounds to pull this off.
只是它并不像听起来那么容易。
- you have to dynamically include required jars at runtime (or include them in the classpath for your application)
- you have to put the plugin in a sandbox that prevents compromising critical classes to the other application
- 您必须在运行时动态包含所需的 jar(或将它们包含在您的应用程序的类路径中)
- 您必须将插件放在沙箱中,以防止将关键类危及其他应用程序
And this calls for a customized classloader. But be warned - there are some well hidden pitfalls in implementing that. On the other hand it's a great exercise.
这需要定制的类加载器。但请注意 - 在实现这一点时存在一些隐藏的陷阱。另一方面,这是一个很好的练习。
So, take your pick: either quick and dirty or hard but rewarding.
因此,请选择:要么快速而肮脏,要么努力但有益。
回答by Michael Rutherfurd
I had a similiar problem. I needed to run a section of Java code in a seperate VM as it invoked native code via JNI that occasionally blew up taking out the entire VM.
我有一个类似的问题。我需要在单独的 VM 中运行一段 Java 代码,因为它通过 JNI 调用本机代码,有时会炸毁整个 VM。
I cheated a little though. I initially used Runtime to invoke a simple batch command file and put the work-in-progress java command in there. This enabled me to tweak it as needed and to run the command in a DOS prompt for easy testing. Once it was finished I simply copied the result into the Runtime invocation.
虽然我有点作弊。我最初使用 Runtime 来调用一个简单的批处理命令文件并将工作中的 java 命令放在那里。这使我能够根据需要调整它并在 DOS 提示符下运行命令以便于测试。完成后,我只需将结果复制到运行时调用中。
回答by Michael Rutherfurd
public class Test {
public static void main(String[] args) throws Exception {
Process p = Runtime.getRuntime().exec("\"c:/program files/windows/notepad.exe\"");
p.waitFor();
}
}
The above works quite well, instead of passing \"c:/program files/windows/notepad.exe\" as the arguments for the executable, use the path to your program, I'm not sure if this solution is JVM version dependent, or if it can use relative paths.
以上工作得很好,而不是将 \"c:/program files/windows/notepad.exe\" 作为可执行文件的参数,使用程序的路径,我不确定这个解决方案是否依赖于 JVM 版本,或者是否可以使用相对路径。