简体   繁体   English

在eclipse,cmd和jar中运行时的工作目录

[英]Working directory when run in eclipse, cmd, and jar

I'm writing a Java program which will execute an external file ~/Java/exampleProject/bin/import.sh . 我正在编写一个Java程序,它将执行一个外部文件~/Java/exampleProject/bin/import.sh My program is under package gqqnbig . 我的程序在gqqnbig软件包gqqnbig So the directory structure is 所以目录结构是

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

When I debug the program in eclipse, the working directory is ~/Java/exampleProject/ . 当我在eclipse中调试程序时,工作目录为~/Java/exampleProject/ I have to execute bin/import.sh . 我必须执行bin/import.sh

When I run the program in cmd, the current directory is ~/Java/exampleProject/bin, my code will not find import.sh . 当我在cmd中运行该程序时,当前目录为〜/ Java / exampleProject / bin,我的代码将找不到import.sh

The program has to be portable (distribute with import.sh). 该程序必须是可移植的 (随import.sh一起分发)。 With the correct directory structure, it should work in my computer as well as in your computer, so I cannot hard code the path of import.sh . 使用正确的目录结构,它应该在我的计算机以及您的计算机上都可以工作 ,因此我无法对import.sh的路径进行硬编码

I also want to pack it into a single jar file . 我也想将其打包到一个jar文件中 The desired structure is (Figure 1) 所需的结构是(图1)

bin/
    import.sh
    program.jar

So how can my program find import.sh when run in eclipse, cmd and jar? 那么,当我的程序在eclipse,cmd和jar中运行时,如何找到import.sh?

UPDATE 更新

I ask my question in another way. 我用另一种方式问我的问题。 Please implement getAbsolutePath function, so that no matther the code is running in eclipse, in cmd, or as a jar file in a folder which also has import.sh (See Figure 1), the output is identical. 请实现getAbsolutePath函数,以使该代码不再在eclipse,cmd中或以jar文件形式在也具有import.sh的文件夹中运行(参见图1),其输出是相同的。

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

Here's a method pulled from one of my projects. 这是从我的一个项目中提取的方法。 It get's the folder that the jar file is located in as opposed to the directory if was run from if invoked on the command line. 如果在命令行上调用了jar文件,那么它将获得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;
    }
}

You can then use that directory to make a File object for your shell script File shellScript = new File(getApplicationRootFolder(), scriptFilename); 然后,您可以使用该目录为外壳脚本创建File对象File shellScript = new File(getApplicationRootFolder(), scriptFilename);


EDIT: Follow up questions to try to help you out and a solution 编辑:跟进问题以尝试帮助您和解决方案

So you want to be able to access one file that has three locations depending on when/where you code is run. 因此,您希望能够访问一个文件,该文件具有三个位置,具体取决于运行代码的时间/位置。 This is how I see those cases: 我就是这样看这些情况的:

Case 1: Running directly from Eclipse (unpackaged code): 情况1:直接从Eclipse运行(未打包的代码):

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

Case 2: Running the packaged jar (shell script inside): 情况2:运行打包的jar(内部的shell脚本):

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

Case 3: Running the packaged jar (shell script external): 情况3:运行打包的jar(外部shell脚本):

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

What I think you need to do is prioritise the order you look at these locations and fall back to the next one in line if the shell script isn't found. 我认为您需要做的是优先考虑在这些位置的顺序,如果找不到shell脚本,则退回到下一行。 I'd guess you want: 我猜你想要:

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

So to access these you will need to write each separately and move through each until you get File.exists() == true . 因此,要访问这些文件,您需要分别编写每个文件,并逐个浏览直到获得File.exists() == true

Something like what follows. 如下所示。 Note I didn't test this and there are likely errors. 请注意,我没有对此进行测试,并且可能存在错误。 I'll leave you to sort them out. 我让你把它们整理一下。 My code is based on the assumptions made above, again I'll leave you to modify the code based on any incorrect guesses. 我的代码基于上述假设,再次,我将让您根据任何错误的猜测来修改代码。

So here's a class with one public method taking a filename argument and returning an InputStream. 因此,这是一个带有一个公共方法的类,该方法带有文件名参数并返回InputStream。 I opted for InputStream in all cases as once you package up your jar you cannot access the resources as File objects any more, only Streams. 在所有情况下,我都选择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();
    }
}

But with all that being said a better way to sort this would be to ensure that the file exists on disk and create it if not found. 但话虽这么说,一种更好的排序方式是确保文件存在于磁盘上并在找不到时创建它。 Then execute the script from disk. 然后从磁盘执行脚本。

I would like to know a definitive answer for this myself. 我自己想知道一个明确的答案。

As a workaround I would put 'import.sh' inside the exampleProject and change the relative path to 'import.sh'. 解决方法是将“ import.sh”放入exampleProject并将相对路径更改为“ import.sh”。

In theory that should work inside Eclipse, and as a packaged Jar file with program.jar and import.sh in the same directory. 从理论上讲,它应该在Eclipse内部运行,并作为带有program.jar和import.sh的打包Jar文件位于同一目录中。

It won't work on the cmd prompt unfortunately, maybe someone can suggest a better method. 不幸的是,它无法在cmd提示符下运行,也许有人可以建议一种更好的方法。

-Kaz -哈兹

I composed a solution. 我制定了一个解决方案。 Call getExecutablePath() to get unified path. 调用getExecutablePath()以获取统一路径。

public static File getExecutablePath()
{

    String workingDirectory = System.getProperty("user.dir");

    File binFile = new File(workingDirectory, "bin");
    if (binFile.exists() && (new File(workingDirectory, "src")).exists())
    {
        return binFile;
    }
    else if (isRunningFromJar())
        return getApplicationRootFolder();
    else
        return new File(workingDirectory);

}

public static boolean isRunningFromJar()
{
    String className = SystemHelper.class.getName().replace('.', '/');
    String classJar = SystemHelper.class.getResource("/" + className + ".class").toString();
    return classJar.startsWith("jar:");
}

/**
 * Retrieve a File representation of the folder this application is located in.
 * 
 * @return
 */
private static File getApplicationRootFolder()
{
    try
    {
        String path = SystemHelper.class.getProtectionDomain().getCodeSource().getLocation().getPath();
        String decodedPath;

        decodedPath = URLDecoder.decode(path, "UTF-8");

        File jarfile = new File(decodedPath);
        return jarfile.getParentFile();
    }
    catch (UnsupportedEncodingException e)
    {
        throw new RuntimeException(e);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM