我正在编写一个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");
}
答案 0 :(得分:3)
这是从我的一个项目中提取的方法。它是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
案例2:运行打包的jar(内部shell脚本):
shell script: X:/Java/YourJar.jar/bin/import.sh
class file: X:/Java/YourJar.jar/bin/gqqnbig/YourClass.class
案例3:运行打包的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
。
如下所示。注意我没有测试这个并且可能存在错误。我会让你把它们整理出来。我的代码基于上面的假设,我将再次根据任何不正确的猜测修改代码。
所以这是一个带有一个公共方法的类,它接受一个文件名参数并返回一个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();
}
}
但是,尽管如此,对此进行排序的更好方法是确保文件存在于磁盘上并在未找到时创建它。然后从磁盘执行脚本。
答案 1 :(得分:1)
我想知道一个明确的答案。
作为一种解决方法,我会把'import.sh'在exampleProject中,并将相对路径更改为' import.sh'。
理论上,它应该在Eclipse中工作,并作为一个打包的Jar文件与program.jar和import.sh在同一目录中。
不幸的是,它不能在cmd提示符上工作,也许有人可以提出更好的方法。
-Kaz
答案 2 :(得分:0)
我写了一个解决方案。调用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);
}
}