swift MacOS:如何获得文件的“上次打开”属性?

cuxqih21  于 2022-11-21  发布在  Swift
关注(0)|答案(1)|浏览(263)

在操作系统的某些文件中存在“上次打开”属性:

可以通过以下方式获取已修改和已打开的属性:

  1. //modified date
  2. try? FileManager.default.attributesOfItem(atPath: url.path)[FileAttributeKey.modificationDate] as? Date
  3. //creation date
  4. try? FileManager.default.attributesOfItem(atPath: url.path)[FileAttributeKey.creationDate] as? Date

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

vulvrdjw

vulvrdjw1#

当然,没有办法获取文件最后一次被打开的时间。相反,你必须获取文件最后一次被读取、写入的时间,或者它的目录项被修改的时间。
Leo在评论中建议使用URLResourceValues.contentAccessDate作为另一个答案,这可能是最简洁的方法,特别是因为您已经有了一个URL,这是目前的典型情况。

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

您还可以使用以下路径向下访问BSD层:

  1. import Darwin // or Foundation
  2. func lastAccessDate(forFileAtPath path: String) -> Date?
  3. {
  4. return path.withCString
  5. {
  6. var statStruct = Darwin.stat()
  7. guard stat($0, &statStruct) == 0 else { return nil }
  8. return Date(
  9. timeIntervalSince1970: TimeInterval(statStruct.st_atimespec.tv_sec)
  10. )
  11. }
  12. }

如果指定的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变体中可用。在没有birthtime的文件系统上,此字段设置为0(即epoch)。
man页引用32位成员字段名称,但同样的情况也适用于64位名称st_atimespecst_mtimespecst_ctimespecst_birthtimespec
为了近似获取文件最后一次打开的时间,你可能需要获取st_atimespecst_mtimespec的最新版本,如果你还想包含对目录项的更改,而这些更改不会修改内容,比如重命名文件或设置其权限,那么你可能需要这样的东西:

  1. func lastReadOrWrite(forFileAtPath path: String) -> Date?
  2. {
  3. return path.withCString
  4. {
  5. var statStruct = Darwin.stat()
  6. guard stat($0, &statStruct) == 0 else { return nil }
  7. let lastRead = Date(
  8. timeIntervalSince1970: TimeInterval(statStruct.st_atimespec.tv_sec)
  9. )
  10. let lastWrite = Date(
  11. timeIntervalSince1970: TimeInterval(statStruct.st_mtimespec.tv_sec)
  12. )
  13. // If you want to include dir entry updates
  14. let lastDirEntryChange = Date(
  15. timeIntervalSince1970: TimeInterval(statStruct.st_ctimespec.tv_sec)
  16. )
  17. return max( lastRead, max(lastWrite, lastDirEntryChange) )
  18. }
  19. }

或使用URLResourceValues

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

当然,如果某个进程只是打开了一个文件,然后在没有阅读的情况下关闭了它,这将不会引起注意,但是如果它没有读写,它打开了文件又有什么关系呢?

展开查看全部

相关问题