监视文件更改时打开的文件太多

时间:2020-04-27 05:59:39

标签: ios swift monitoring grand-central-dispatch ipados

我正在为iPad开发基于文档浏览器的应用程序。我一直在使用SKQueue来监视文件的更改,以确保当用户在文档浏览器中执行操作时它们的元数据保持最新。启动监视的代码:

    // Set up the queue
    let delegate = self
    queue = SKQueue(delegate: delegate)!
    // Remove all existing paths
    queue?.removeAllPaths()

    // Get the list of PDF URLs using a function that enumerates a folder's contents
    let pdfFiles = getFolderContents(rootFolder: myDocumentsFolder, extensionWanted: "pdf")
    for pdfFilePath in pdfFiles.filePaths {
        queue?.addPath(pdfFilePath.path)
    }
    for pdfFolderPath in pdfFiles.folderPaths {
        queue?.addPath(pdfFolderPath.path)
    }

我开发了自己的逻辑来响应来自此队列的通知,但是在应用程序运行时,我没有从队列中删除任何项目。

问题-似乎当观看的项目数超过200(文件和文件夹)时,系统撞墙并且控制台报告错误24:打开太多文件。之后,将无法执行任何文件的读取/写入。

根据我从搜索中收集到的信息,似乎iOS和iPadOS不允许同时访问超过256个文件描述符,这意味着GCD监视文件更改的方法会受到影响相同的限制。

是否有不受此限制的监视文件更改的方法?还有其他建议吗?

1 个答案:

答案 0 :(得分:2)

经过大量研究和实验,我终于可以确认确实如此,对于MacOS,iOS和iPadOS,打开文件描述符的默认最大允许数目是256。在MacOS中可以轻松更改此设置-请参见文章here。但是,iOS和iPadOS本质上更加封闭,没有可靠的方法可以在这些平台上更改此限制。

因此,好的做法是:

  1. 尝试避免设计会调用太多文件描述符的应用。
  2. 监控目录,而不是单个文件。使用大多数可用于监视文件系统的工具,您会收到有关受监视目录中任何文件更改的通知。通过枚举文件夹并将其新状态与保存状态进行比较,只需从那里实施逻辑即可。您可以在此SO thread的前两个答案中找到合适的代码。

注意:我建议使用枚举而不是其他获取文件系统状态的方法,因为其他方法往往会在模拟器和实际设备之间产生不兼容的结果(对符号链接解析的不同处理)。

  1. 确保可以查询选择的监视文件系统的方法以查看正在监视的项目数,并在用户接近设置的限制时发出警报。请记住,这256个打开的文件还必须包括该应用程序使用的所有文件,包括应用程序捆绑包中的文件和实际使用的文件。因此,请注意安全性。

在我的情况下,我的应用程序使用UIDocumentBrowserViewController或换句话说-Apple自己的“文件”应用程序,以允许用户管理其文件。我必须使元数据与文件系统状态保持最新,并且无法控制用户的文件管理习惯。使事情复杂化的是,“文件”应用程序本身可以用于修改该应用程序的文件系统-当我的应用程序不处于活动状态时。

因此,我要做两件事:

  1. 我将App Delegate的applicationDidEnterBackground和applicationWillTerminate方法的文件系统的详细状态保存到Application Support中的json文件中,并在应用程序启动时将其与文件系统的新枚举进行比较-并提醒用户注意任何不匹配,建议下次使用该应用程序自己的文件浏览器。
  2. 我创建了自己的快速软件包,名为SFSMonitor,用于监视文件系统。它基于非常方便的SKQueue(我强烈建议),但是它不是监视kevent,而是使用了Dispatch Sources-Apple提倡的一种更现代的方法。它类似于Apple自己的目录监视器(您可以在其中找到here的参考文件),但是它无需监视一个目录,而是允许您创建和管理它们的整个队列。此类允许您设置最大数量的受监视文件描述符,并在达到该限制时得到通知。