管理 Linux 最近文件列表

freedesktop 定制了最近的文件存储规范 desktop-bookmark-spec,为 X 桌面提供统一的标准,它存储在 ~/.local/share/recently-used.xbel 这个文件里,使用 UTF-8 编码,按照 XBEL 格式来存储,所谓 XBEL 就是书签标记语言(XML Bookmark Exchange Language),是一个 XML 扩展的格式,用于表示书签和其他类似 Web 链接集合的格式;对于管理方法就是像 FAM 那样的机制监控文件的变化,当有变化时做出相应的动作,比如文件被移除就在 GUI 上进行移除的操作,GUI 上提供移除的操作,当移除时就会在 xbel 删除对应的元素,然后改变 xbel 文件内容。

基本格式

xbel 文件基本格式如下:

<?xml version="1.0" encoding="UTF-8"?>
<xbel version="1.0"
      xmlns:bookmark="http://www.freedesktop.org/standards/desktop-bookmarks"
      xmlns:mime="http://www.freedesktop.org/standards/shared-mime-info"
>
  <bookmark href="file:///home/rekols/Desktop/test.txt" added="2018-11-01T16:32:08Z" modified="2018-11-01T16:32:46Z" visited="2018-11-01T16:32:09Z">
    <info>
      <metadata owner="http://freedesktop.org">
        <mime:mime-type type="text/plain"/>
        <bookmark:groups>
          <bookmark:group>gedit</bookmark:group>
        </bookmark:groups>
        <bookmark:applications>
          <bookmark:application name="gedit" exec="&apos;gedit %u&apos;" modified="2018-11-01T16:32:46Z" count="4"/>
        </bookmark:applications>
      </metadata>
    </info>
  </bookmark>
</xbel>

根元素必须是 xbel,version 为 1.0,其他属性可以忽略;

每个书签都必须以 bookmark 元素为节点,书签的 URI 必须存储在 href 属性中;每个 bookmark元素 都应该有 added、modified、visited 属性,并且以 ISO 8601 为规范的字符串,必须以 UTC 编码,所以读取的时候需要把 UTC 转换为本地时钟才是正确的。

每个 metadata 元素可以按照以下元素顺序任意组合:

  • mime-type 是强制性的,必须包含 URI 指向目标的 MIME Type。
  • groups 元素包含一个 group 元素列表,每个元素包含一个组名,groups 元素不是必要的。
  • applications 元素包含一个 application 元素列表,指的是该 URI 用什么应用程序打开的。

每个 application 元素都有很多属性,name 属性是应用程序的名称,exec 属性是启动时的命令行,count 是打开的次数,modified 是最后一次打开的时间。

xbel 读取

在通常情况下我们只关心 XML 元素的读取,所以 Qt 提供了一个快速解析类:QXmlStreamReader,可以从 QIODevice 或原始的 QByteArray 中读取数据,通过循环 readNextStartElement() 获取每一个 bookmark 元素的 href、added、modified 等属性的内容,还可以使用一组方便的函数 isStartElement()、text() 来获取…

QFile file(QDir::homePath() + "/.local/share/recently-used.xbel");

if (file.open(QIODevice::ReadOnly)) {
    QXmlStreamReader reader(&file);

    while (!reader.atEnd()) {
        if (!reader.readNextStartElement() ||
             reader.name() != "bookmark") {
            continue;
        }

        const QStringRef &location = reader.attributes().value("href");
        const QStringRef &added = reader.attributes().value("added");

        if (!location.isEmpty()) {
            qDebug() << "文件链接: " << location.toString() 
                     << "加入时间: " << added.toString();
        }
    }
}

调用 reader 的 attributes() 获得所有属性,然后对返回的对象使用 value() 即可拿到属性的内容。

移除文件

移除文件并不是把原始文件移动到回收站,而是从最近文件中移除,所以就需要在 xbel 文件上移除某个元素,然后保存文件。

QString need_remove_url = "xxxxxxxxxxxxxx";

QFile file(QDir::homePath() + "/.local/share/recently-used.xbel");
if (!file.open(QIODevice::ReadOnly)) {
    QDomDocument doc;
    doc.setContent(&file);
    file.close();

    // 根元素
    QDomElement root = doc.documentElement();
    // 返回 root 所有 bookmark 元素列表
    QDomNodeList node_list = root.elementsByTagName("bookmark");

    // 遍历所有 bookmark 元素,找到属性内容然后移除
    for (int i = 0; i < node_list.count(); ) {
        // 获取 bookmark 中的 URI
        const QString file_url = node_list.at(i).toElement().attribute("href");

        if (file_url == need_remove_url) {
            root.removeChild(node_list.at(i));
            m_recentNodes.remove(file_url);
        } else {
            ++i;
        }
    }

    // 写入文件
    if (file.open(QIODevice::WriteOnly)) {
        QTextStream out(&file);
        out << doc.toString();
    }
}

相关链接

https://www.freedesktop.org/wiki/Specifications/desktop-bookmark-spec/

https://blog.rekols.com/linux/2018/11/02/linux-recent-manager.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注