观察 macOS 上的文件打开和关闭

问题描述 投票:0回答:1

我想查看文件的打开和关闭情况。我已经尝试过不同的方法,例如

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
        }
    }
}

swift macos
1个回答
0
投票

我找到了这个链接: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,谁访问了这个特定文件。不幸的是,有两个缺点:

  1. 我需要使用计时器尽可能频繁地检查文件是否仍然打开。

  2. 不知何故,有时需要很长时间才能意识到文件是否关闭。因此,关闭后,尽管文件已关闭,该函数仍会返回应用程序的进程 ID。但似乎

    lsof
    有时也有同样的问题。

© www.soinside.com 2019 - 2024. All rights reserved.