我正在编写一个 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/