我想查看文件的打开和关闭情况。我已经尝试过不同的方法,例如
kqueue
或FSEventStreamCreate
。不幸的是,如果文件被关闭,这些都不会显示出来。
这是否可能,如果可以,我该如何在 Swift 中做到这一点?
编辑
我还找到了有关使用
lsof
的解决方案。这确实向我展示了文件是否打开或关闭,但我需要使用计时器尽可能频繁地调用 lsof
来查明文件是打开还是关闭。所以我认为这不是一个好的解决方案。
编辑2
按照要求,这是我如何使用的示例
FSEventStream
:
class FileWatcher {
private var fileURLs: [URL]
private var stream: FSEventStreamRef?
init(fileURLs: [URL]) {
self.fileURLs = fileURLs
}
deinit {
stopWatching()
}
func startWatching() {
let paths = fileURLs.map { $0.path() } as CFArray
let callback: FSEventStreamCallback = { _, _, _, eventPaths, _, _ in
print(eventPaths.load(as: Int32.self))
}
var context = FSEventStreamContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
stream = FSEventStreamCreate(nil, callback, &context, paths, FSEventStreamEventId(kFSEventStreamEventIdSinceNow), 1, FSEventStreamCreateFlags(kFSEventStreamCreateFlagFileEvents))
FSEventStreamSetDispatchQueue(stream!, DispatchQueue.init(label: "watching"))
FSEventStreamStart(stream!)
}
func stopWatching() {
if let stream = stream {
FSEventStreamStop(stream)
FSEventStreamInvalidate(stream)
FSEventStreamRelease(stream)
self.stream = nil
}
}
}
我找到了这个链接:https://lists.apple.com/archives/cocoa-dev/2010/May/msg01455.html
翻译成 Swift 我有这个功能:
func pidsAccessingPath(_ path: String) -> [Int32] {
var result: [Int32] = []
let pathFileSystemRepresentation = FileManager.default.fileSystemRepresentation(withPath: path)
var pidsSize = 0
var pids: UnsafeMutablePointer<pid_t>?
let listpidspathResult = proc_listpidspath(UInt32(PROC_ALL_PIDS), 0, pathFileSystemRepresentation, UInt32(PROC_LISTPIDSPATH_EXCLUDE_EVTONLY), nil, 0)
guard listpidspathResult >= 0 else {
return []
}
pidsSize = Int(listpidspathResult > 0 ? listpidspathResult : 1)
pids = UnsafeMutablePointer<pid_t>.allocate(capacity: pidsSize)
guard let pidsPointer = pids else {
return []
}
let secondListpidspathResult = proc_listpidspath(UInt32(PROC_ALL_PIDS), 0, pathFileSystemRepresentation, UInt32(PROC_LISTPIDSPATH_EXCLUDE_EVTONLY), pidsPointer, Int32(pidsSize))
guard secondListpidspathResult >= 0 else {
pids?.deallocate()
return []
}
let pidsCount = Int(secondListpidspathResult) / MemoryLayout<pid_t>.size
for i in 0..<Int(pidsCount) {
result.append(pidsPointer[i])
}
pids?.deallocate()
return result
}
到目前为止似乎有效,我得到了进程 ID,谁访问了这个特定文件。不幸的是,有两个缺点:
我需要使用计时器尽可能频繁地检查文件是否仍然打开。
不知何故,有时需要很长时间才能意识到文件是否关闭。因此,关闭后,尽管文件已关闭,该函数仍会返回应用程序的进程 ID。但似乎
lsof
有时也有同样的问题。