【问题标题】:Simple Java Desktop App: Config files and where to put them简单的 Java 桌面应用程序:配置文件及其放置位置
【发布时间】:2016-12-26 18:58:50
【问题描述】:

这感觉像是一个绝对的新手问题,但我对什么应该是一个基本的问题非常感兴趣。

我正在用 Java 编写一个简单的桌面应用程序。 (实际上是 Scala,但让它过去吧。)它针对 Windows 机器。我想打包它并让它在不创建安装程序或弄乱 Windows 注册表的情况下运行。我想要一个用户可以找到和编辑的配置文件,以便自定义设置。 (例如,以 SublimeText 的用户偏好的方式。)

我设想以下结构:

my-application/
|- bin/
   |- myApp.class (or myApp.jar, if you prefer)
|- files/
   |- config/
      |- config.json
   |- output/
      |- output.xlsx
|-runMyApp.bat

在 Eclipse 中,相对路径倾向于解析为 myApplication/ 目录,但如果我从命令行运行应用程序,它们会解析为 -cp 参数。 (通常是bin/ 目录。)

我是不是太天真了?我是不是完全搞错了范式?

在我看来,能够始终如一地在可执行文件周围的文件系统中定位文件(资源)是一件基本的事情。

请帮忙!

【问题讨论】:

  • 向我们展示您的代码。
  • 路径是相对于运行程序的工作目录,而不是类路径。
  • 为什么不将配置文件存储在用户的主目录中?在我看来,大多数原生 Windows 应用程序都是这样做的(通常在 Documents 文件夹中,以便用户可以轻松找到它们,或者在隐藏的 AppData 文件夹中,如果用户通常不需要直接访问它们)。
  • 如果我理解正确你的问题,你想传递一个 conf 文件,它将在 app jar 之外,这意味着如果用户没有注意你的 .readme 文件,他们可以把它在任何地方。那你为什么不用文件选择器放一个简单的傻表单,并在启动时提示用户,但在你的应用程序完全初始化之前,将配置文件传递给你。现在您可以保存用户首选项,每次开始之前您都会加载该文件,或者您可以每次都提示,当然还有您对验证规则或文件未找到等的自定义处理。

标签: java eclipse scala relative-path


【解决方案1】:

打包应用程序意味着将类放入 .jar 文件中,该文件是一个 zip 文件,其中包含一个或多个特定于 Java 的特殊条目。 (有很多 Stack Overflow 答案描述了如何做到这一点,例如 Java: export to an .jar file in eclipse 。请随意搜索。)

问题是,应用程序无法写入自己的 .jar 文件。在 Windows 上,文件可能被锁定且不可写;在其他系统上,这可能是可能的,但由于许多原因这是一个坏主意。您应该始终认为 .jar 文件是只读的。

由于配置需要是可写的,它不能存在于您的 .jar 文件中,但您的 .jar 文件可以(并且应该)包含您的 config.json 作为 默认 配置。实际配置应该是用户主目录下的某个文件;如果它不存在,您的程序应该将您的默认配置复制到该位置以允许将来修改。或者,您的程序可以忽略丢失的配置并默认读取内部打包的默认配置,但在这种情况下,您需要为最终用户提供可写配置文件格式的完整文档,因为他们没有示例路过。

打包在 .jar 文件中的文件称为 resources,使用 Class.getResourceClass.getResourceAsStream 方法读取。您不能使用 File 或 Path 对象读取它们,因为它们是 zip 存档的一部分,而不是实际文件。将其复制到可写位置通常如下所示:

Path userConfigFile = /* ... */;

try (InputStream defaultConfig = getClass().getResourceAsStream("/config/config.json")) {
    Files.copy(defaultConfig, userConfigFile);
}

有关阅读资源的更多信息,您可能想阅读Access to Resources

在 Windows 上,配置文件的实际位置通常在用户 AppData 目录的子目录中:

Path configParent;

String appData = System.getEnv("APPDATA");
if (appData != null) {
    configParent = Paths.get(appData);
} else {
    configParent = Paths.get(
        System.getProperty("user.home"), "AppData", "Local");
}

Path configDir = configParent.resolve(applicationName);
Files.createDirectories(configDir);

Path userConfigFile = configDir.resolve("config.json");

如果您有兴趣讨论在其他平台上放置用户配置文件的位置,请参阅 this questionthis one

【讨论】:

    【解决方案2】:

    File 类默认解析用户当前工作目录中的相对路径(可作为系统属性user.dir 获得)。因此,如果您在命令行上执行cd 以切换到一个目录,然后调用 Java 应用程序,那么从 Java 应用程序的角度来看,该目录将是当前用户的工作目录。

    您可以做的一件事是将基本目录作为系统属性传递给 Java 应用程序。这可以在使用自己的位置启动应用程序的 shell 脚本中完成。

    另一种可能性是在调用 Java 应用程序时将配置文件等文件包含在类路径中,并从 Java 应用程序中的类路径加载它们。这种解决方案的缺点是用户可以做比需要做的事情更多的事情,这可能会导致损坏。

    【讨论】:

    • 了解系统属性,以及如何传递它们,是我需要的启示。我想我可以研究其余的。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-06
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 2019-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多