消灭泛滥的点文件:XDG 基准目录规范

泛滥的点文件

很多应用程序会在用户的主目录($HOME/)下创建自己的 . 文件/文件夹(dotfiles)。这些文件默认在系统中是隐藏的。这么做的目的大部分是跨平台地存储“永久”的用户配置、文件等。而这种做法的后果就是主目录下被各种这类的隐藏文件充斥。

我的主目录下三分之二是这类文件……
我的主目录下三分之二是这类文件……

用户删除或者移动无法解决这个问题。因为应用程序探测到该目录下没有它的地盘后,会试图再次初始化一个新的。

我之前在写一个 Java 游戏应用程序的时候,为了保留用户的得分数据,也采用了这个做法。获取到用户的主目录后,在其下开拓一片自己的天地,开始“为所欲为”……

1
2
private static final String STORAGE_PATH =
System.getProperty("user.home") + File.separator + ".mygame" + File.separator;

而我记得确实是尝试搜索了 “Best Practice” 呀!(……)

这种做法的弊端显而易见:用户难以控制,点文件泛滥成灾;应用程序也很难进行版本维护。

此外,有人曾在 2012 年发出了警惕:https://plus.google.com/+RobPikeTheHuman/posts/R58WgWwN9jp。大致意思是,很多年前,Unix 系统的点文件在执行 ls 后其实是显示的,以此让导航变得容易便捷,Unix 的开发者后来加了这么句话把它们藏了起来:

1
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) continue;

自此,很多程序员便开始把他们的应用程序附加文件丢到用户主目录中。

XDG 基准目录规范(XDG Base Directory Specification)

幸运的是,在 FreeDesktop.org 保护伞的共同努力下,形成了 XDG 基准目录规范(XDG Base Directory Specification)。该规范的目的就是为了解决以上所述的问题。

该规范的诞生已经有年头了,我在 WebArchive 上发现最早可追溯到 2010 年。当时已是 0.6 版本,现在(2019 年)是 0.7。

该规范定义了一套指向应用程序的环境变量,这些变量指明的就是这些程序应该存储的基准目录。而变量的具体值取决于用户,若用户未指定,将由程序本身指向一个默认目录,该默认目录也应该遵从标准,而不是用户主目录。

环境变量清单:用户层面变量(User-Level Variables)

$XDG_DATA_HOME

$XDG_DATA_HOME 定义了应存储用户特定的数据文件的基准目录。默认值是 $HOME/.local/share

使用场景:

  • 用户下载的插件;
  • 程序产生的数据库;
  • 用户输入历史、书签、邮件等。

$XDG_CONFIG_HOME

$XDG_CONFIG_HOME 定义了应存储用户特定的配置文件的基准目录。默认值是 $HOME/.config

使用场景:

  • 用户配置。

一般来说,这个地方可以在程序初始化的时候存储一个默认的配置文件供加载和修改。

$XDG_CACHE_HOME

$XDG_CACHE_HOME 定义了应存储用户特定的非重要性数据文件的基准目录。默认值是 $HOME/.cache

使用场景:

  • 缓存的缩略图、歌曲文件、视频文件等。

程序应该做到哪怕这个目录被用户删了也能正常运行。

$XDG_RUNTIME_DIR

$XDG_RUNTIME_DIR 定义了应存储用户特定的非重要性运行时文件和一些其他文件对象。

使用场景:

  • 套接字 (socket)、命名管道 (named pipes) 等。

该目录必须由用户拥有,并且该用户必须是唯一具有读写访问权限的。 目录的 Unix 访问模式必须是 0700

环境变量清单:系统层面变量(System-Level Variables)

$XDG_CONFIG_DIRS

$XDG_CONFIG_DIRS 定义了一套按照偏好顺序的基准目录集,用来搜索除了 $XDG_CONFIG_HOME 目录之外的配置文件。该目录中的文件夹应该用冒号(:)隔开。默认值是 /etc/xdg

使用场景:

  • 可以被用户特定的配置文件所覆盖的系统层面的配置文件。

一般来说,应用程序安装的时候可以加载配置文件到这个目录。

$XDG_DATA_DIRS

$XDG_DATA_DIRS 定义了一套按照偏好顺序的基准目录集,用来搜索除了 $XDG_DATA_HOME 目录之外的数据文件。该目录中的文件夹应该用冒号(:)隔开。默认值是 /usr/local/share/:/usr/share/

使用场景:

  • 可以被所有用户使用的插件或者主题。

一般来说,应用程序安装的时候可以加载插件、主题等文件到这个目录。

使用

这套标准的使用也很简单。读取相关的环境变量即可;若读取的结果是未定义的,则使用该标准定义的相应默认存储目录。之后再在基准目录下创建一个程序特定的目录(一般用程序的名字)去存储数据。比如说:如果要存储配置文件,在 $XDG_CONFIG_HOME/your-program 下存储。

这样一来,用户如果移动了文件,可以通过修改这套环境变量的方式来安全迁移。

迁移

如果你还在使用老一套($HOME/.your-prgram),也可以很容易地迁移到这套标准。程序打开时依照标准初始化这些文件,同时也检查旧位置的文件达到兼容旧版本的目的。