获取执行文件的当前路径

时间:2018-12-29 23:40:28

标签: java

我尝试在我的Java项目文件Books.txt中写入和读取该文件。 问题是,只有partialPath具有文件的完整路径时,我才能访问文件。

代码如下:

openssl enc -in ciphertext -out binarytext -d -a
openssl rsautl -decrypt -in binarytext -out plaintext -inkey private_key

如果我如上所述设置相对路径,则会得到找不到异常文件的信息。

我的问题是如何以编程方式设置当前目录的完整路径?

3 个答案:

答案 0 :(得分:1)

这里是我编写的code snippet代码中的Drombler Commons - Client Startup,以确定可执行jar的位置。将DromblerClientStarter替换为主类。 至少当您将应用程序作为可执行JAR文件运行时,此方法应该有效。

/**
 * The jar URI prefix "jar:"
 */
private static final String FULL_JAR_URI_PREFIX = "jar:";
/**
 * Length of the jar URI prefix "jar:"
 */
private static final int FULL_JAR_URI_PREFIX_LENGTH = 4;

private Path determineMainJarPath() throws URISyntaxException {
    Class<DromblerClientStarter> type = DromblerClientStarter.class;
    String jarResourceURIString = type.getResource("/" + type.getName().replace(".", "/") + ".class").toURI().
            toString();
    int endOfJarPathIndex = jarResourceURIString.indexOf("!/");
    String mainJarURIString = endOfJarPathIndex >= 0 ? jarResourceURIString.substring(0, endOfJarPathIndex)
            : jarResourceURIString;
    if (mainJarURIString.startsWith(FULL_JAR_URI_PREFIX)) {
        mainJarURIString = mainJarURIString.substring(FULL_JAR_URI_PREFIX_LENGTH);
    }
    Path mainJarPath = Paths.get(URI.create(mainJarURIString));
    return mainJarPath;
}

根据在应用程序分发包中捆绑 Books.txt 的位置,可以使用此mainJarPath确定 Books.txt 的路径。

答案 1 :(得分:0)

我还认为,通常由运行中的Java应用程序创建的文件(以及以后可能修改和/或删除的文件)最好放在文件系统的位置,该位置应远离Java应用程序安装的主目录。对于Windows操作系统,示例可能是 “ C:\ ProgramData \ ApplicationNameFiles \” ,对于other OS platforms则类似。在我看来,至少对于我来说,由于驱动器维护不良或打开文件资源管理器并决定自行使用该文件的用户意外删除,它对基本应用程序文件造成损坏的可能性较小清理其系统中所谓的不必要的文件,以及其他不太明显的原因。

由于Java几乎可以在任何平台上运行,并且此类数据文件位置是特定于平台的,因此应允许用户选择可以在其中创建和操作这些文件的位置。然后可以将该位置另存为属性。确实,还有更多工作要做,但是恕我直言,我认为这很值得。

在首次启动JAR文件的安​​装主目录中创建目录(文件夹),然后从那里存储和操作应用程序创建的数据文件时,显然要容易得多。绝对更容易找到,但是再来一次……那将是见解,而不是我的。但是,如果您打算这样做,那么Java应用程序的Install Utility绝对应该知道该安装路径在哪里,因此只需将该位置存储在某个地方即可。

没有安装实用程序?那么,那么您的Java应用程序肯定需要一种方法来知道您JAR文件从何处运行,以下代码是实现此目的的一种方法:

public String applicationPath(Class mainStartupClassName) {
    try {
        String path = mainStartupClassName.getProtectionDomain().getCodeSource().getLocation().getPath();
        String pathDecoded = URLDecoder.decode(path, "UTF-8");
        pathDecoded = pathDecoded.trim().replace("/", File.separator);
        if (pathDecoded.startsWith(File.separator)) {
            pathDecoded = pathDecoded.substring(1);
        }
        return pathDecoded;
    }
    catch (UnsupportedEncodingException ex) {
        Logger.getLogger("applicationPath() Method").log(Level.SEVERE, null, ex);
    }
    return null;
}

这是使用此方法的方式:

String appPath = applicationPath(MyMainStartupClassName.class);

请记住:如果此方法是在IDE中运行的,则很可能不会将路径返回到JAR文件,而是指向为应用程序存储类的文件夹构建。

答案 2 :(得分:0)

这不是Java独有的问题,这是任何希望将数据本地写入磁盘的语言开发人员所面临的问题。这个问题有很多部分。

如果您希望能够写入文件(大概是读取更改),则需要设计一种解决方案,以独立于平台的方式查找文件。

一些问题

程序的安装位置

尽管大多数操作系统确实有一些约定对此进行规范,但这并不意味着由于某种原因它们总是被使用。

此外,在某些操作系统上,您会受到积极限制,无法写入“安装”位置。 Windows 8+不允许您写入“ Program Files”目录,在Java中,这通常(或至少在我处理该问题时)无提示地失败。

在MacOS上,如果您使用的是“应用程序捆绑包”,则工作目录会自动设置为用户的主目录,这使得管理起来更加困难

执行上下文(或工作目录)可能与程序的安装位置不同

程序可以安装在一个位置,但是可以从另一个位置执行,这将更改工作目录的位置。许多命令行工具都受到此问题的困扰,并使用不同的约定来解决它(永远不知道JAVA_HOME环境变量是做什么的)

受限制的磁盘访问

许多操作系统现在都在积极锁定程序可以写入的位置,即使具有管理员权限也是如此。

可重用的解决方案...

大多数OS都提出了解决此问题的约定,不仅适用于Java,而且适用于所有希望在该平台上工作的开发人员。

重要像所有准则一样,这些规则不是一成不变的规则,而是平台作者提出的建议,旨在使您的生活更轻松,并使平台的操作更安全< / p>

最常见的解决方案是将文件简单地放在磁盘上的“众所周知的位置”,可以通过绝对路径访问该文件,而与程序的安装或执行位置无关。

在Windows上,这意味着将文件放入~\AppData\Local\{application name}~\AppData\Roaming\{application name}

在MacOS上,这意味着将文件放入~/Library/Application Data/{application name}

在* nix上,这通常意味着将文件放入~/.{application name}

可以说您可以在所有三个平台上使用~/.{application name},但是作为“显示隐藏文件”的用户,我希望您不会污染我的主目录。

可能的,可重用的解决方案...

Windows 8发行时,我遇到了“您无法写成Program Files”的问题,这花费了一些时间进行诊断,因为它没有产生异常,只是失败了。 >

我也在Mac OS上进行了更多工作,因此我需要一个简单的跨平台解决方案,因此我的代码可以自动适应,而每个平台不需要多个分支。

为此,我附带了一个简单的实用程序类...

public enum SystemUtilities {

    INSTANCE;

    public boolean isMacOS() {
        return getOSName().startsWith("Mac");
    }

    public boolean isMacOSX() {
        return getOSName().startsWith("Mac OS X");
    }

    public boolean isWindowsOS() {
        return getOSName().startsWith("Windows");
    }

    public boolean isLinux() {
        return getOSName().startsWith("Linux");
    }

    public String getOSName() {
        return System.getProperty("os.name");
    }

    public File getRoamingApplicationSupportPath() {
        // For *inx, use '~/.{AppName}'
        String path = System.getProperty("user.home");
        if (isWindowsOS()) {
            path += "\\AppData\\Roaming";
        } else if (isMacOS()) {
            path += "/Library/Application Support";
        }
        return new File(path);
    }

    public File getLocalApplicationSupportPath() {
        // For *inx, use '~/.{AppName}'
        String path = System.getProperty("user.home");
        if (isWindowsOS()) {
            path += "\\AppData\\Local";
        } else if (isMacOS()) {
            path += "/Library/Application Support";
        }
        return new File(path);
    }

}

这提供了一个基线,可从中构建“独立”代码,例如,您可以使用类似...

File appDataDir = new File(SystemUtilities.INSTANCE.getLocalApplicationSupportPath(), "MyAwesomeApp");
if (appDataDir.exists() || appDataDir.mkdirs()) {
    File fileToWrite = new File(appDataDir, "Books.txt");
    //...
}

读取/写入文件。尽管就我个人而言,我可能会让经理/工厂进行这项工作并将引用返回到末尾File,但这就是我。

“预打包”文件如何?

三种可能的解决方案...

  1. 创建文件(如果文件不存在),并根据需要使用默认值填充文件
  2. 从“ Jar”文件中复制“模板”文件(如果不存在)
  3. 使用安装程序来安装文件-这是我们在更改所有“外部”配置文件的位置时使用的解决方案。

只读文件...

对于只读文件,最简单的解决方案是将它们作为“嵌入式资源”嵌入Jar中,这使查找和管理更加容易...

URL url = getClass().getResource("/path/to/readOnlyResource.txt");

如何执行此操作,将取决于您的构建系统