【问题标题】:MacOS: how to get "Last opened" attribute of file?MacOS:如何获取文件的“上次打开”属性?
【发布时间】:2022-11-20 03:20:42
【问题描述】:

在 OS 中的某些文件中存在“上次打开”属性:

modified 和 opened 属性可以通过以下方式获取:

//modified date
try? FileManager.default.attributesOfItem(atPath: url.path)[FileAttributeKey.modificationDate] as? Date

//creation date
try? FileManager.default.attributesOfItem(atPath: url.path)[FileAttributeKey.creationDate] as? Date

但是如何获得“最后打开”的日期呢?

【问题讨论】:

    标签: swift macos file


    【解决方案1】:

    AFAIK,没有办法得到文件的最后一次打开.相反,你必须得到最后一次,书面或其目录条目已被修改。

    Leo 在 cmets 中关于使用 URLResourceValues.contentAccessDate 的另一个答案的建议可能是最干净的方法,特别是因为您已经有一个 URL,这在最近很常见。

    func lastAccessDate(forURL url: URL) -> Date?
    {
        return try? url.resourceValues(
            forKeys: [.contentAccessDateKey]).contentAccessDate
    }
    

    您还可以使用以下路径深入到 BSD 层:

    import Darwin // or Foundation
    
    func lastAccessDate(forFileAtPath path: String) -> Date?
    {
        return path.withCString
        {
            var statStruct = Darwin.stat()
            guard  stat($0, &statStruct) == 0 else { return nil }
            return Date(
                timeIntervalSince1970: TimeInterval(statStruct.st_atimespec.tv_sec)
            )
        }
    }
    

    如果指定的 URL 是符号链接,我不是 100% 的 resourceValues 的行为,但 stat() 将返回有关链接指向的文件系统 inode 的信息。如果您想直接了解有关链接本身的信息,请改用lstat()stat()lstat() 在其他方面是一样的。

    我很确定 URLResourceValues.contentAccessDate 在后台使用 stat()lstat()

    要记住的一件事是最后访问时间是不是上次打开文件的时间,而是最后一次打开文件的时间. statman 页面说:

    struct stat与时间相关的字段如下:

    st_atime 上次访问文件数据的时间。由 mknod(2)、utimes(2) 和 read(2) 系统调用更改。

    st_mtime 最后一次修改文件数据的时间。由 mknod(2)、utimes(2) 和 write(2) 系统调用更改。

    st_ctime 最后一次更改文件状态(inode 数据修改)的时间。由 chmod(2)、chown(2)、link(2)、mknod(2)、rename(2)、unlink(2)、 utimes(2) 和 write(2) 系统调用。

    st_birthtime 文件创建时间。仅在创建文件时设置一次。该字段仅在 64 位 inode 变体中可用。在文件系统上 出生时间不可用,此字段设置为 0(即纪元)。

    man 页面指的是 32 位成员字段名称,但同样适用于 64 位名称,st_atimespecst_mtimespecst_ctimespecst_birthtimespec

    为了近似获取上次打开文件的时间,您需要获取最新的 st_atimespecst_mtimespecst_ctimespec,如果您还想包含对不包含的目录条目的更改修改内容,例如重命名文件或设置其权限。所以你需要这样的东西:

    func lastReadOrWrite(forFileAtPath path: String) -> Date?
    {
        return path.withCString
        {
            var statStruct = Darwin.stat()
            guard  stat($0, &statStruct) == 0 else { return nil }
            let lastRead = Date(
                timeIntervalSince1970: TimeInterval(statStruct.st_atimespec.tv_sec)
            )
            let lastWrite = Date(
                timeIntervalSince1970: TimeInterval(statStruct.st_mtimespec.tv_sec)
            )
    
            // If you want to include dir entry updates
            let lastDirEntryChange = Date(
                timeIntervalSince1970: TimeInterval(statStruct.st_ctimespec.tv_sec)
            )
    
            return max( lastRead, max(lastWrite, lastDirEntryChange) )
        }
    }
    

    或使用URLResourceValues

    func lastReadOrWriteDate(forURL url: URL) -> Date?
    {
        let valKeys: Set<URLResourceKey> =
            [.contentAccessDateKey, .contentModificationDateKey, .attributeModificationDateKey]
    
        guard let urlVals = try? url.resourceValues(forKeys:valKeys)
        else { return nil }
    
        let lastRead      = urlVals.contentAccessDate         ?? .distantPast
        let lastWrite     = urlVals.contentModificationDate   ?? .distantPast
    
        // If you want to include dir entry updates
        let lastAttribMod = urlVals.attributeModificationDate ?? .distantPast
    
        return max(lastRead, max(lastWrite, lastAttribMod))
    }
    
    

    当然,如果某个进程只是打开一个文件然后在没有读取或写入的情况下关闭它,那将不会被注意到,但是如果它没有读取或写入,它打开文件有关系吗?

    【讨论】:

    • 双重检查 - 上次访问和上次打开的日期不同......示例:如果你打开“应用程序”文件夹并将按上次打开日期对其进行排序 - 它的排序方式与你的代码排序方式不同“上次访问日期”
    • @Andrew___Pls_Support_UA,我更新了我的答案。我展示的两种方法实际上都获得了文件的最后一次, 但不包括它是什么时候书面.另请记住,如果您要与 Applications 文件夹的 Finder 结果进行比较,Finder 会在其 UI 中合并 /Applications/System/Applications 时发挥一些魔力。除非您进行类似的合并,否则您不会在您的应用程序中获得相同的结果。
    猜你喜欢
    • 2021-12-24
    • 1970-01-01
    • 2018-02-09
    • 2016-01-15
    • 1970-01-01
    • 2022-10-14
    • 2017-06-20
    • 2011-12-13
    • 2011-06-22
    相关资源
    最近更新 更多