Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/379.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何检查路径中是否存在程序_Java_Scala_Runtime - Fatal编程技术网

Java 如何检查路径中是否存在程序

Java 如何检查路径中是否存在程序,java,scala,runtime,Java,Scala,Runtime,我正在用scala编写一个程序,该程序调用: Runtime.getRuntime().exec( "svn ..." ) 我想检查“svn”是否可以从命令行获得(即,它可以在路径中访问)。 我该怎么做 PS:我的程序设计为在windows上运行,我不是scala程序员,但我在任何语言中都会执行类似于“svn help”的操作,只是检查exec方法的返回代码(0或1)。。。如果失败,svn不在路径中:P Runtime rt = Runtime.getRuntime(); Process pr

我正在用scala编写一个程序,该程序调用:

Runtime.getRuntime().exec( "svn ..." )
我想检查“svn”是否可以从命令行获得(即,它可以在路径中访问)。 我该怎么做


PS:我的程序设计为在windows上运行,我不是scala程序员,但我在任何语言中都会执行类似于“
svn help
”的操作,只是检查exec方法的返回代码(0或1)。。。如果失败,svn不在路径中:P

Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("svn help");
int exitVal = proc.exitValue();

按照惯例,值0表示正常终止。

关于原始问题,我还将检查是否存在FMF建议的问题

我还想指出,您必须至少处理流程的输出,读取可用数据,这样流就不会被填满。否则,这将导致进程阻塞

为此,请使用proc.getInputStream()(对于System.out)和proc.getErrorStream()(对于System.err)检索进程的InputStreams,并读取不同线程中的可用数据


我只是告诉你,因为这是一个常见的陷阱,svn可能会产生相当多的输出,所以请不要对离题性投反对票;)

如果您安装了cygwin,您可以首先调用“which svn”,如果它位于可执行路径中,它将返回svn的绝对路径,否则“which:no svn in(…)”。对“which”的调用将返回exitValue 1(如果未找到),或0(如果找到)。您可以使用FMF详细信息的方式检查此错误代码。

以下是Java 8解决方案:

stringexec=;
boolean existsInPath=Stream.of(System.getenv(“PATH”).split(Pattern.quote(File.pathSeparator)))
.map(路径::get)
.anyMatch(path->Files.exists(path.resolve(exec));
anyMatch(…)
替换为
filter(…).findFirst()
以获取完全限定路径


下面是一个跨平台静态方法,用于比较常见的可执行扩展:

导入java.io.File;
导入java.nio.file.path;
导入java.util.stream.stream;
导入静态java.io.File.pathSeparator;
导入静态java.nio.file.Files.isExecutable;
导入静态java.lang.System.getenv;
导入静态java.util.regex.Pattern.quote;
公共静态布尔canExecute(最终字符串exe){
最终var路径=getenv(“路径”).split(引号(路径分隔符));
返回Stream.of(path).map(path::get).anyMatch(
路径->{
最终变量p=path.resolve(exe);
var=false;
对于(最终var扩展:扩展){
if(可执行(路径为(p.toString()+扩展))){
发现=真;
打破
}
}
发现退货;
}
);
}

这应该解决对第一个解决方案的大多数批评。除此之外,迭代系统环境变量可以避免硬编码扩展,但也有其自身的缺点。

Selenium在类中有一个相当完整的Windows/Linux/Mac实现,自Selenium 3.1以来具有
public
访问权限(以前只能通过不推荐的方法
org.openqa.selenium.os.CommandLine#find
)访问。不过它是ASL2.0

请注意,
ExecutableFinder
在Windows上无法理解-它只是有一组硬编码的可执行文件扩展名(.exe、.com、.bat)。

此代码在Windows上使用“where”命令和“which”命令,检查系统是否知道路径中所需的程序。如果找到,函数将返回程序的java.nio.file.PATH,否则返回null

我在Windows7和LinuxMint17.3上用Java8测试了它

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Logger;


public class SimulationUtils
{
    private final static Logger LOGGER = Logger.getLogger(SimulationUtils.class.getName());

    public static Path lookForProgramInPath(String desiredProgram) {
        ProcessBuilder pb = new ProcessBuilder(isWindows() ? "where" : "which", desiredProgram);
        Path foundProgram = null;
        try {
            Process proc = pb.start();
            int errCode = proc.waitFor();
            if (errCode == 0) {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
                    foundProgram = Paths.get(reader.readLine());
                }
                LOGGER.info(desiredProgram + " has been found at : " + foundProgram);
            } else {
                LOGGER.warning(desiredProgram + " not in PATH");
            }
        } catch (IOException | InterruptedException ex) {
            LOGGER.warning("Something went wrong while searching for " + desiredProgram);
        }
        return foundProgram;
    }

    private static boolean isWindows() {
        return System.getProperty("os.name").toLowerCase().contains("windows");
    }
}
要使用它:

    System.out.println(SimulationUtils.lookForProgramInPath("notepad"));
在我的Windows 7系统上,它显示:

C:\Windows\System32\notepad.exe

在linux上:

    System.out.println(SimulationUtils.lookForProgramInPath("psql"));
/usr/bin/psql

这种方法的优点是,它可以在任何平台上工作,不需要解析PATH环境变量或查看注册表。即使找到了所需的程序,也不会调用。最后,不需要知道程序扩展名。Windows下的gnuplot.exe和Linux下的gnuplot都可以通过相同的代码找到:

    SimulationUtils.lookForProgramInPath("gnuplot")

欢迎提出改进建议!

根据我的经验,仅通过使用
ProcessBuilder
调用命令来判断命令是否存在是不可能的(无论是
异常还是返回值似乎都不一致)

下面是一个Java7解决方案,它遍历
路径
环境变量并查找匹配的工具。将检查目录中的所有文件。
matchesExecutable
必须是忽略扩展名和大小写的工具名

public static File checkAndGetFromPATHEnvVar(final String matchesExecutable) {
    String[] pathParts = System.getenv("PATH").split(File.pathSeparator);
    for (String pathPart : pathParts) {
        File pathFile = new File(pathPart);

        if (pathFile.isFile() && pathFile.getName().toLowerCase().contains(matchesExecutable)) {
            return pathFile;
        } else if (pathFile.isDirectory()) {
            File[] matchedFiles = pathFile.listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    return FileUtil.getFileNameWithoutExtension(pathname).toLowerCase().equals(matchesExecutable);
                }
            });

            if (matchedFiles != null) {
                for (File matchedFile : matchedFiles) {
                    if (FileUtil.canRunCmd(new String[]{matchedFile.getAbsolutePath()})) {
                        return matchedFile;
                    }
                }
            }
        }
    }
    return null;
}
以下是帮助者:

public static String getFileNameWithoutExtension(File file) {
        String fileName = file.getName();
        int pos = fileName.lastIndexOf(".");
        if (pos > 0) {
            fileName = fileName.substring(0, pos);
        }
        return fileName;
}

public static boolean canRunCmd(String[] cmd) {
        try {
            ProcessBuilder pb = new ProcessBuilder(cmd);
            pb.redirectErrorStream(true);
            Process process = pb.start();
            try (BufferedReader inStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                while ((inStreamReader.readLine()) != null) {
                }
            }
            process.waitFor();
        } catch (Exception e) {
            return false;
        }
        return true;
}
这与的答案类似,但它也解决了在
path
环境变量中存在无效路径的罕见情况。这将导致
InvalidPathException

private static final String ENVIRONMENT_VARIABLES_TEXT = System.getenv("PATH");

private static boolean isCommandAvailable(String executableFileName)
{
    String[] environmentVariables = ENVIRONMENT_VARIABLES_TEXT.split(File.pathSeparator);
    for (String environmentVariable : environmentVariables)
    {
        try
        {
            Path environmentVariablePath = Paths.get(environmentVariable);
            if (Files.exists(environmentVariablePath))
            {
                Path resolvedEnvironmentVariableFilePath = environmentVariablePath.resolve(executableFileName);
                if (Files.isExecutable(resolvedEnvironmentVariableFilePath))
                {
                    return true;
                }
            }
        } catch (InvalidPathException exception)
        {
            exception.printStackTrace();
        }
    }

    return false;
}

总的来说,这可能是目前最有效和最健壮的解决方案。

我认为最好是使用“哪个svn”而不是“svn帮助”。它仍然会给出正确的返回码,说明路径中是否存在svn,但如果成功,您还将获得svn可执行文件的完整路径。“where”是Windows的“which”等价物在尝试获取退出值之前,您必须调用Process#waitFor()。请看它现在是公共的:谢谢@gouessej。看起来它还不是发布的一部分:当我尝试在IDE中运行它时(我正在使用Eclipse),它找不到已将其路径添加到我的环境路径变量中的文件。但是,当我从它创建可运行的JRE并从我的终端运行该JRE时,它可以工作。因此,我怀疑我在IDE中的路径与我打开终端时的路径不一样。我如何解决这个问题?我不希望每次都创建可运行的Jar测试代码。谢谢!我也不会让它在Windows上工作。如果我设置
exec=java
,我会得到一个错误的结果。但是如果我