3

我正在使用 FileObserver 来监视文件夹中的更改。

事件按预期触发,但我在区分事件中的文件和目录时遇到问题,因为在触发事件DELETEMOVED_FROM,调用两者File.isFile()File.isDirectory()是错误的(这是有道理的)。

在删除文件之前是否有有效的方法进行此检查?通过列出受影响文件夹中的所有文件,我确实有一个解决方法,但是它效率低下。

文件观察器代码:

 mFileObserver = new FileObserver(DIRECTORY.getPath()) {
            @Override
            public void onEvent(int event, String path) {
                event &= FileObserver.ALL_EVENTS;
                switch (event) {
                    case (CREATE):
                    case (MOVED_TO):
                        Log.d(TAG, "Added to folder: " + DIRECTORY + " --> File name " + path);
                        addChild(path);
                        break;
                    case (DELETE):
                    case (MOVED_FROM):
                        Log.d(TAG, "Removed from folder " + DIRECTORY + " --> File name " + path);                            
                        removeChild(path);
                        break;
                    case (MOVE_SELF):
                    case (DELETE_SELF):
                        removeDirectory();
                        break;
                }
            }               
        };

编辑:

这就是文件/文件夹的评估方式removeChild(String)

private void removeChild(String name) {

        mFileObserver.stopWatching();

        String filepath = this.getAbsolutePath() + separator + name;
        File file = new File(filepath);
        if (file.exists())
            Log.d(TAG, "Exists");
        else Log.d(TAG, " Does not Exists");

        if (file.isDirectory())
            Log.d(TAG, "is Directory");
        else Log.d(TAG, " is  NOT Directory");

        if (file.isFile())
            Log.d(TAG, "is File");
        else Log.d(TAG, " is  NOT File");
    }

相关的logcat输出是:

04-03 12:37:20.714 5819-6352:  Removed from folder /storage/emulated/0/Pictures/GR --> File name ic_alarm_white_24dp.png
04-03 12:37:20.714 5819-6352:  Does not Exists
04-03 12:37:20.714 5819-6352:  is  NOT Directory
04-03 12:37:20.714 5819-6352:  is  NOT File
4

1 回答 1

3

在删除文件之前是否有有效的方法进行此检查?

不幸的是,我不知道。这是有道理的——文件系统事件是已经发生的事情。

FileObserver用于inotify获取事件。inotify可以在https://www.ibm.com/developerworks/library/l-inotify/找到对功能的良好描述:

使用 inotify 监控 Linux 文件系统事件

...

在inotify 之前有dnotify。不幸的是,dnotify 有一些限制,让用户希望得到更好的东西。inotify 的一些优点是:

  • Inotify 使用单个文件描述符,而 dnotify 需要为您打算监视更改的每个目录打开一个文件描述符。当您同时监视多个目录时,这可能会非常昂贵,甚至可能达到每个进程的文件描述符限制。
  • inotify 使用的文件描述符是通过系统调用获得的,并且没有关联的设备或文件。使用 dnotify,文件描述符固定目录,防止卸载支持设备,这是可移动媒体的一个特殊问题。使用 inotify,卸载的文件系统上的监视文件或目录会生成一个事件,并且自动删除监视。
  • Inotify 可以监视文件或目录。Dnotify 监视目录,因此程序员必须保留 stat 结构或反映正在监视的目录中的文件的等效数据结构,然后将它们与事件发生后的当前状态进行比较,以便了解目录中的条目发生了什么。
  • 如上所述,inotify 使用文件描述符,允许程序员使用标准选择或轮询函数来监视事件。这允许高效的多路复用 I/O 或与 Glib 的主循环集成。相比之下,dnotify 使用信号,程序员经常发现信号更难或不够优雅。在内核 2.6.25 中还添加了信号驱动 IO 通知以进行 inotify。

inotify 的 API

...

请注意,没有提及“即将发生的事件”或类似的内容。

您不需要保留所有文件的列表 - 您只需要一个目录列表 - 一个简单的Set<String>应该就可以了。如果删除String path在集合中,则它是一个目录。

对于更健壮的方法,当您启动监视时,您还可以FileObserver对主要监视的目录中的所有目录进行监视(还可以在创建监视程序后将监视添加到主目录中创建的每个目录)。

然后,如果您DELETE_SELF从其中一个子FileObserver对象中获取 a,您就会知道它是一个目录。如果事件没有获得事件的关联子FileObserver对象DELETE_SELF,则它不是目录。

对于一个非常大的目录,这种方法无疑会存在可伸缩性问题......

于 2018-04-05T21:15:28.020 回答