java - 在 eclipse、cmd 和 jar 中运行时的工作目录

标签 java eclipse

我正在编写一个 Java 程序,它将执行一个外部文件 ~/Java/exampleProject/bin/import.sh。我的程序在包 gqqnbig 下。所以目录结构是

exampleProject/
  bin/
    import.sh
    gqqnbig/
      *.class

我在eclipse中调试程序时,工作目录是~/Java/exampleProject/。我必须执行 bin/import.sh

当我在cmd中运行程序时,当前目录是~/Java/exampleProject/bin,我的代码找不到import.sh

程序必须是可移植的(使用 import.sh 分发)。有了正确的目录结构,它应该可以在我的电脑和你的电脑上运行,所以我不能对 import.sh 的路径进行硬编码

我也想把它打包成一个 jar 文件。想要的结构是(图1)

bin/
    import.sh
    program.jar

那么我的程序在eclipse、cmd、jar中运行时如何找到import.sh呢?

更新

我用另一种方式问我的问题。请实现getAbsolutePath 函数,这样无论代码是在eclipse、cmd 中运行,还是作为jar 文件在也有import.sh 的文件夹中运行(参见图1),输出都是相同的.

public static void main(String[] args)
{
    System.out.println("Look for "+getAbsolutePath()+"\\import.sh");
}

最佳答案

这是从我的一个项目中提取的方法。如果在命令行上调用,它会获取 jar 文件所在的文件夹,而不是从中运行的目录。

/**
 * Retrieve a File representation of the folder this application is
 * located in.
 * 
 * @return
 */
private static File getApplicationRootFolder()
{
    String path = FileGetter.class.getProtectionDomain().getCodeSource()
            .getLocation().getPath();
    try
    {
        String decodedPath = URLDecoder.decode(path, "UTF-8");
        File jarParentFolder = new File(decodedPath).getParentFile();
        if (jarParentFolder.exists() && jarParentFolder.canRead()
        {
            File shellScript = new File(jarParentFolder, "import.sh")
    }
    catch (UnsupportedEncodingException e)
    {
        Main.myLog.error(TAG, "Unencoding jar path failed on:\n\t" + path);
        e.printStackTrace();
        return null;
    }
}

然后您可以使用该目录为您的 shell 脚本创建一个文件对象 File shellScript = new File(getApplicationRootFolder(), scriptFilename);


编辑:跟进问题以尝试帮助您解决问题

因此,您希望能够根据运行代码的时间/地点访问具有三个位置的一个文件。这就是我对这些案例的看法:

案例 1:直接从 Eclipse 运行(未打包的代码):

shell script:    X:/Java/exampleProject/bin/import.sh
class file:      X:/Java/exampleProject/bin/gqqnbig/YourClass.class

案例二:运行打包后的jar(里面有shell脚本):

shell script:    X:/Java/YourJar.jar/bin/import.sh
class file:      X:/Java/YourJar.jar/bin/gqqnbig/YourClass.class

案例三:运行打包好的jar(外部shell脚本):

shell script:    X:/Java/import.sh
class file:      X:/Java/YourJar.jar/bin/gqqnbig/YourClass.class

我认为您需要做的是确定查看这些位置的顺序,如果未找到 shell 脚本,则回退到下一个位置。我猜你想要:

1. external to jar
2. inside packaged jar
3. unpackaged

因此,要访问这些文件,您需要分别编写并遍历每个文件,直到获得 File.exists() == true

类似下面的内容。请注意,我没有对此进行测试,并且可能存在错误。我会让你去解决它们。我的代码基于上述假设,我将再次让您根据任何不正确的猜测修改代码。

所以这是一个带有一个公共(public)方法的类,该方法接受一个文件名参数并返回一个 InputStream。我在所有情况下都选择了 InputStream,因为一旦你打包了你的 jar,你就不能再以 File 对象的形式访问资源,只能访问 Streams。

public class FileGetter
{

    private static String RESOURCE_DIRECTORY = "bin";

    /**
     * Retrieve an InputStream for a resource file.
     * 
     * @param filename
     * @return
     */
    public InputStream getResourceFileStream(String filename)
    {
        // this is where you decide your preference or the priority of the locations
        InputStream inputStream = null;

        inputStream = getExternalFile(filename);
        if (inputStream != null)
        {
            return inputStream;
        }
        inputStream = getInternalPackagedFile(filename);
        if (inputStream != null)
        {
            return inputStream;
        }
        inputStream = getInternalUnpackagedFile(filename);
        if (inputStream != null)
        {
            return inputStream;
        }

        // couldn't find the file anywhere so log some error or throw an exception
        return null;
    }

    /**
     * Retrieve an InputStream for a file located outside your Jar
     * 
     * @param filename
     * @return
     */
    private static InputStream getExternalFile(String filename)
    {
        // get the jar's absolute location on disk (regardless of current 'working directory')
        String appRootPath = FileGetter.class.getProtectionDomain().getCodeSource()
                .getLocation().getPath();
        try
        {
            String decodedPath = URLDecoder.decode(appRootPath, "UTF-8");
            File jarfile = new File(decodedPath);
            File parentDirectory = jarfile.getParentFile();
            if (testExists(parentDirectory))
            {
                File shellScript = new File(parentDirectory, filename);
                if (testExists(shellScript))
                {
                    return new FileInputStream(shellScript);
                }
            }
        }
        catch (UnsupportedEncodingException e)
        {}
        catch (NullPointerException e)
        {}
        catch (FileNotFoundException e)
        {}
        // if any part fails return null
        return null;
    }

    /**
     * Retrieve an InputStream for a file located inside your Jar.
     * 
     * @param filename
     * @return
     */
    private static InputStream getInternalPackagedFile(String filename)
    {
        // root directory is defined as the jar's root so we start with a "/".
        URL resUrl = FileGetter.class.getResource(File.separator + RESOURCE_DIRECTORY
                + File.separator + filename);
        String badPath = resUrl.getPath();
        String goodPath = badPath.substring(badPath.indexOf("!") + 1);
        InputStream input = FileGetter.class.getResourceAsStream(goodPath);
        // returns null if nothing there so just
        return input;
    }

    private static InputStream getInternalUnpackagedFile(String filename)
    {
        // eclipse will 'cd' to the code's directory so we use relative paths
        File shellScriptFile = new File(RESOURCE_DIRECTORY + File.separator + filename);
        if (testExists(shellScriptFile))
        {
            try
            {
                InputStream shellScriptStream = new FileInputStream(shellScriptFile);
                if (shellScriptStream != null)
                {
                    return shellScriptStream;
                }
            }
            catch (FileNotFoundException e)
            {}
        }
        return null;
    }

    /**
     * Test that a file exists and can be read.
     * 
     * @param file
     * @return
     */
    private static boolean testExists(File file)
    {
        return file != null && file.exists() && file.canRead();
    }
}

但是综上所述,更好的排序方法是确保文件存在于磁盘上,如果找不到则创建它。然后从磁盘执行脚本。

关于java - 在 eclipse、cmd 和 jar 中运行时的工作目录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22493512/

相关文章:

java - 如何让 JAXB 在将元素添加到列表后调用 setter ?

java - 如何将内容写入文件

android - 导入gradle项目,android报错

java - REST Web 项目出现 404 错误

android - 在 Android 应用程序中使用 commonc 编解码器的 NoSuchMethodError

java - Gupta/Centura 到 Java 的转换

java - 获取swing标签文本并将其传递给父类

java - 在 JBoss 5.1 中设置 user.dir 系统属性

java - 不支持 Project facet WebSphere Web(共存)版本 8.0

java - 我如何使用 jvm type -server 测试我的程序