You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用FileManager记录文件上次打开时间时自定义FileAttributeKey失效如何解决

问题根因

你自定义的FileAttributeKey无法持久化的原因是:FileManager.setAttributes(_:ofItemAtPath:)仅支持系统预定义的标准文件属性键,自定义的键值不会被写入到文件系统元数据中,所以二次读取时自然获取不到对应值。

推荐解决方案

方案1:使用扩展属性(xattr,跨平台通用,支持持久化自定义元数据)

扩展属性是文件系统级别的自定义元数据存储方案,可以持久化保存任意自定义键值,适合给文件附加独立于文件内容的标记信息。
Swift读写示例:

写入上次打开时间

import Foundation

func setLastOpenedDate(_ date: Date, forPath path: String) throws {
    let data = try JSONEncoder().encode(date)
    // 扩展属性名建议加App专属前缀避免冲突
    let attrName = "com.yourapp.lastOpenedAt"
    try data.withUnsafeBytes { buffer in
        let result = setxattr(path, attrName, buffer.baseAddress, buffer.count, 0, 0)
        if result == -1 {
            throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: nil)
        }
    }
}

// 调用示例
do {
    try setLastOpenedDate(Date(), forPath: videoNameDirectoryPath)
} catch {
    Log.error(error.localizedDescription)
}

读取上次打开时间

func getLastOpenedDate(forPath path: String) throws -> Date? {
    let attrName = "com.yourapp.lastOpenedAt"
    // 先获取属性长度
    let length = getxattr(path, attrName, nil, 0, 0, 0)
    guard length != -1 else {
        // 不存在对应属性
        return nil
    }
    var data = Data(count: length)
    let result = data.withUnsafeMutableBytes { buffer in
        getxattr(path, attrName, buffer.baseAddress, buffer.count, 0, 0)
    }
    guard result != -1 else {
        throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: nil)
    }
    return try JSONDecoder().decode(Date.self, from: data)
}

适用场景:需要和其他App共享该标记、文件存储位置不固定的场景。

方案2:本地映射表存储

如果文件仅在你的App沙盒内使用,不需要对外共享打开时间标记,可以直接在本地维护一个文件路径(或者文件唯一标识)和打开时间的映射表,存储到UserDefaults或者独立的plist文件中。
优点是读写速度更快,不需要调用文件系统接口,适合文件数量不多的场景。

方案3:使用系统预定义的最后使用时间属性

macOS/iOS的Spotlight元数据里有kMDItemLastUsedDate键,记录了文件最后一次被用户打开的时间,无需自己维护,直接读取即可:

import CoreServices

func getSystemLastUsedDate(forPath path: String) -> Date? {
    let url = URL(fileURLWithPath: path)
    guard let mdItem = MDItemCreateWithURL(kCFAllocatorDefault, url as CFURL) else {
        return nil
    }
    return MDItemCopyAttribute(mdItem, kMDItemLastUsedDate) as? Date
}

注意:该属性仅对Spotlight索引覆盖范围内的文件有效,沙盒内部分目录、外置存储未被索引的文件可能读取不到。


内容的提问来源于stack exchange,提问作者Michael Jajou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 00:27:00