java 获取本地应用程序数据目录路径的跨平台方法是什么?

hfwmuf9z  于 2022-12-28  发布在  Java
关注(0)|答案(7)|浏览(172)

我需要的是一种独立于平台的方法来获取本地应用程序数据目录的路径。System.getenv("LOCALAPPDATA")似乎只能在Windows上工作。我该如何着手呢?

sxpgvts3

sxpgvts31#

你可以这样说(如果我错了,或者这是一个糟糕的方法,就反驳我)

private String workingDirectory;
//here, we assign the name of the OS, according to Java, to a variable...
private String OS = (System.getProperty("os.name")).toUpperCase();
//to determine what the workingDirectory is.
//if it is some version of Windows
if (OS.contains("WIN"))
{
    //it is simply the location of the "AppData" folder
    workingDirectory = System.getenv("AppData");
}
//Otherwise, we assume Linux or Mac
else
{
    //in either case, we would start in the user's home directory
    workingDirectory = System.getProperty("user.home");
    //if we are on a Mac, we are not done, we look for "Application Support"
    workingDirectory += "/Library/Application Support";
}
//we are now free to set the workingDirectory to the subdirectory that is our 
//folder.

注意,在这段代码中,我充分利用了Java在处理目录时将'/''\\'视为相同的特性,Windows使用'\\'作为pathSeparator,但它也很喜欢使用'/'(至少Windows 7是这样的)。我们可以同样容易地说workingDirectory = System.getenv("APPDATA");,它也会同样有效。

n3ipq98p

n3ipq98p2#

我个人认为appdirs对于类似的用例非常有用,它提供了定位不同类型的有用目录的函数:

  • getUserDataDir
  • getUserConfigDir
  • getUserCacheDir
  • getUserLogDir
  • 看起来这是你需要的一个
  • getSiteConfigDir

它返回的位置或多或少是标准的:

dsekswqp

dsekswqp3#

这个问题很老了,但是我缺少一个列出环境变量的答案,而不是一些有趣的绝对路径。我对OSX一无所知。这个帖子只包含Windows和Linux的信息。
我没有足够的分数来扩展一个已经存在的答案,所以我必须写一个新的。

**Linux:**As previously mentioned there exists something like freedesktop.org which is defining a standard the linux distributions are trying to fulfill. There is also a subpage defining environment variables and their default values (If they are not set they are empty by default. The application has to match the variable to the default). Link to that page: freedesktop.org env vars

    • 定义的与此问题相关的变量:**
    • $XDG_DATA_HOME*(* 本地 )(默认为:$主页/.本地/共享*)
    • $XDG配置主页*(* 本地 )(默认值为:$主页/. config*)
    • $XDG_DATA_DIRS*(* 全局 )(默认为: */用户/本地/共享//用户/共享/**)
    • $XDG_CONFIG_DIRS*(* 全局 )(默认为:/等/xdg*)
    • Windows XP操作系统:**
      • %APPDATA %(默认值为:* * C:\文档和设置{用户名}\应用程序数据
      • %公用程序文件%(默认为:* * C:\Program Files\Common Files)(共享程序文件)
      • %公用程序文件(x86)%(默认为:* * C:\Program Files(x86)\公用文件)(仅限64位!)(共享程序文件)
      • %程序文件%(默认为:* * %系统驱动器%\程序文件
      • %程序文件(x86)%(默认值为:* * % SystemDrive %\Program Files(x86)(仅限64位版本)(仅限64位!)
    • Windows Vista+操作系统:**
      • %APPDATA %(默认值为:* * C:\Users {username}\AppData\Roaming)(在链接的工作站之间共享。用户本地。保存文件和配置)
      • %本地数据%(默认值为:* * C:\用户{用户名}\应用程序数据\本地)(用户本地。保存文件和配置)
      • %公用程序文件%(默认为:* * C:\Program Files\Common Files)(共享程序文件)
      • %公用程序文件(x86)%(默认为:* * C:\Program Files(x86)\公用文件)(仅限64位!)(共享程序文件)
      • %程序文件%(默认为:* * % SystemDrive %\Program Files)(安装后不会更改的静态数据)
      • %程序文件(x86)%(默认值为:* * % SystemDrive %\Program Files(x86)(仅限64位版本))(仅限64位!)(安装后不会更改的静态数据)
      • %程序数据%(默认值为:* * % SystemDrive %\ProgramData)(影响所有用户的可更改数据)
    • 简而言之:**Linux有两个环境变量可能没有设置(一个用于配置,一个用于文件)。Windows据我所知只有一个环境变量同时用于配置和文件。请使用这些而不是绝对路径。
xytpbqjk

xytpbqjk4#

对于中等数量的数据,考虑java.util.prefs.Preferences,提到here,或者javax.jnlp.PersistenceService,讨论here

pokxtpni

pokxtpni5#

没有跨平台的方法,因为不同的操作系统使用的概念太不同了,无法“抽象”。我不熟悉 *nix和Mac的约定,但在Windows上没有“主文件夹”,应用程序必须指定是否要将内容存储在 * 漫游配置文件 *(默认为C:\Users\<username>\AppData\Roaming\<application vendor>\<application name>\)或 * 本地配置文件 *(默认为C:\Users\<username>\AppData\Local\<application vendor>\<application name>\)中。
请注意,您不能硬编码这些路径,因为在网络安装中,它们可能位于其他位置。您也不应该依赖环境变量,因为用户可以修改它们。您的应用程序应该调用Windows API的SHGetKnownFolderPath函数。
两者之间的区别在于,本地配置文件是特定于用户和计算机的,而漫游配置文件是特定于用户的,所以在像我的大学这样的设置中,放在漫游配置文件中的东西应用程序会上传到服务器,并同步到我登录的任何一台计算机。
应用程序应该负责选择它们想要存储的设置是本地的还是漫游的。不幸的是,Java不允许应用程序决定这一点。相反,有一个全局用户可配置的设置来决定你将获得哪个文件夹。

t3psigkw

t3psigkw6#

这是对其他StackOverflow答案以及appdata项目的一些想法的总结,没有引入对JNA的依赖。存在对Apache Commons Lang3的依赖,可以通过使用System.getProperty( "os.name" )的返回值来消除,如其他地方所示。

代码

请注意,我没有在除Linux以外的任何平台上测试过:

import java.io.FileNotFoundException;
import java.nio.file.Path;

import static java.lang.System.getProperty;
import static java.lang.System.getenv;
import static org.apache.commons.lang3.SystemUtils.*;

/**
 * Responsible for determining the directory to write application data, across
 * multiple platforms. See also:
 *
 * <ul>
 * <li>
 *   <a href="https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html">
 *     Linux: XDG Base Directory Specification
 *   </a>
 * </li>
 * <li>
 *   <a href="https://learn.microsoft.com/en-us/windows/deployment/usmt/usmt-recognized-environment-variables">
 *     Windows: Recognized environment variables
 *   </a>
 * </li>
 * <li>
 *   <a href="https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html">
 *     MacOS: File System Programming Guide
 *   </a>
 * </li>
 * </ul>
 * </p>
 */
public final class UserDataDir {

  private static final Path UNDEFINED = Path.of( "/" );

  private static final String PROP_USER_HOME = getProperty( "user.home" );
  private static final String PROP_OS_VERSION = getProperty( "os.version" );
  private static final String ENV_APPDATA = getenv( "AppData" );
  private static final String ENV_XDG_DATA_HOME = getenv( "XDG_DATA_HOME" );

  private UserDataDir() { }

  public static Path getAppPath( final String appName )
    throws FileNotFoundException {
    final var osPath = isWindows()
      ? getWinAppPath()
      : isMacOs()
      ? getMacAppPath()
      : isUnix()
      ? getUnixAppPath()
      : UNDEFINED;

    final var path = osPath.equals( UNDEFINED )
      ? getDefaultAppPath( appName )
      : osPath.resolve( appName );

    return ensureExists( path ) ? path : fail( path );
  }

  private static Path fail( final Path path ) throws FileNotFoundException {
    throw new FileNotFoundException( path.toString() );
  }

  private static Path getWinAppPath() {
    return ENV_APPDATA == null || ENV_APPDATA.isBlank()
      ? home( getWinVerAppPath() )
      : Path.of( ENV_APPDATA );
  }

  /**
   * Gets the application path with respect to the Windows version.
   *
   * @return The directory name paths relative to the user's home directory.
   */
  private static String[] getWinVerAppPath() {
    return PROP_OS_VERSION.startsWith( "5." )
      ? new String[]{"Application Data"}
      : new String[]{"AppData", "Roaming"};
  }

  private static Path getMacAppPath() {
    final var path = home( "Library", "Application Support" );

    return ensureExists( path ) ? path : UNDEFINED;
  }

  private static Path getUnixAppPath() {
    // Fallback in case the XDG data directory is undefined.
    var path = home( ".local", "share" );

    if( ENV_XDG_DATA_HOME != null && !ENV_XDG_DATA_HOME.isBlank() ) {
      final var xdgPath = Path.of( ENV_XDG_DATA_HOME );

      path = ensureExists( xdgPath ) ? xdgPath : path;
    }

    return path;
  }

  /**
   * Returns a hidden directory relative to the user's home directory.
   *
   * @param appName The application name.
   * @return A suitable directory for storing application files.
   */
  private static Path getDefaultAppPath( final String appName ) {
    return home( '.' + appName );
  }

  private static Path home( final String... paths ) {
    return Path.of( PROP_USER_HOME, paths );
  }

  /**
   * Verifies whether the path exists or was created.
   *
   * @param path The directory to verify.
   * @return {@code true} if the path already exists or was created,
   * {@code false} if the directory doesn't exist and couldn't be created.
   */
  private static boolean ensureExists( final Path path ) {
    final var file = path.toFile();
    return file.exists() || file.mkdirs();
  }

  private static boolean isWindows() {
    return IS_OS_WINDOWS;
  }

  private static boolean isMacOs() {
    return IS_OS_MAC;
  }

  private static boolean isUnix() {
    return IS_OS_UNIX;
  }
}

测试

用于显示用法的单元测试:

import org.junit.jupiter.api.Test;

import java.io.FileNotFoundException;

import static org.junit.jupiter.api.Assertions.*;

class UserDataDirTest {
  @Test
  void test_Unix_GetAppDirectory_DirectoryExists()
    throws FileNotFoundException {
    final var path = UserDataDir.getAppPath( "test" );
    final var file = path.toFile();

    assertTrue( file.exists() );
    assertTrue( file.delete() );
    assertFalse( file.exists() );
  }
}
sgtfey8w

sgtfey8w7#

你可以用这个

String currentDir = new File(".").getAbsolutePath();

或者这个:

System.getProperty("user.dir")

我更喜欢第一种选择
问候

相关问题