美文网首页
macOS 监听文件夹里文件的状态

macOS 监听文件夹里文件的状态

作者: 木马不在转 | 来源:发表于2023-03-12 11:14 被阅读0次
    工具作用:

    FSEventStreamTool:用于监听某个文件夹里所有文件的操作回调,比如删除、移动、编辑等.多用于NSDocument文档项目的文档状态监听.

    FSEventStreamTool的实现

    .h文件

    /// 文件里的操作类型
    typedef NS_ENUM(NSInteger, FSEventStreamType) {
        /// 有文件创建
        FSEventStreamTypeCreate = 0,
        /// 有文件移动
        FSEventStreamTypeMV,
        /// 有文件移进来了
        FSEventStreamTypeMoveIn,
        /// 有文件移出去了
        FSEventStreamTypeMoveOut,
        /// 有文件删除了
        FSEventStreamTypeRemove,
        /// 有文件修改了
        FSEventStreamTypeModify
    };
    NS_ASSUME_NONNULL_BEGIN
    
    /// 文件监听工具
    @interface FSEventStreamTool : NSObject
    
    /// 监听文件夹
    /// @param paths 文件路径集合
    /// @param callback 回调
    + (FSEventStreamTool *)monitorFileWithPaths:(NSArray <NSString *>*)paths
                        callback:(void(^)(FSEventStreamType type, NSString *path))callback;
    
    /// 取消监听
    - (void)cancelMonitor;
    @end
    

    .m文件

    #import "FSEventStreamTool.h"
    #import <CoreServices/CoreServices.h>
    
    @interface FSEventStreamTool ()
    @property(nonatomic, assign) NSInteger syncEventID;
    @property(nonatomic, assign) FSEventStreamRef syncEventStream;
    @property (nonatomic, copy) void(^callback)(FSEventStreamType type, NSString *path);
    @end
    @implementation FSEventStreamTool
    
    /// 监听文件夹
    /// @param paths 文件路径集合
    /// @param callback 回调
    + (FSEventStreamTool *)monitorFileWithPaths:(NSArray <NSString *>*)paths
                                       callback:(void(^)(FSEventStreamType type, NSString *path))callback {
        FSEventStreamTool *tool = [[FSEventStreamTool alloc] initWithPaths:paths];
        tool.callback = callback;
        return tool;
    }
    - (instancetype)initWithPaths:(NSArray *)paths{
        if (self = [super init]) {
            
            if(self.syncEventStream) {
                FSEventStreamStop(self.syncEventStream);
                FSEventStreamInvalidate(self.syncEventStream);
                FSEventStreamRelease(self.syncEventStream);
                self.syncEventStream = NULL;
            }
            FSEventStreamContext context;
            context.info = (__bridge void * _Nullable)(self);
            context.version = 0;
            context.retain = NULL;
            context.release = NULL;
            context.copyDescription = NULL;
            self.syncEventStream = FSEventStreamCreate(NULL, &fsevents_callback, &context, (__bridge CFArrayRef _Nonnull)(paths), self.syncEventID, 1, kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagUseCFTypes);
            FSEventStreamScheduleWithRunLoop(self.syncEventStream, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
            FSEventStreamStart(self.syncEventStream);
        }
        return self;
    }
    
    /// 取消监听
    - (void)cancelMonitor {
        
        if(self.syncEventStream) {
            FSEventStreamStop(self.syncEventStream);
            FSEventStreamInvalidate(self.syncEventStream);
            FSEventStreamRelease(self.syncEventStream);
            self.syncEventStream = NULL;
            self.callback = nil;
        }
    }
    
    #pragma mark - private method
    -(void)updateEventID {
        self.syncEventID = FSEventStreamGetLatestEventId(self.syncEventStream);
    }
    #pragma mark - setter
    -(void)setSyncEventID:(NSInteger)syncEventID{
        [[NSUserDefaults standardUserDefaults] setInteger:syncEventID forKey:@"SyncEventID"];
    }
    -(NSInteger)syncEventID {
        NSInteger syncEventID = [[NSUserDefaults standardUserDefaults] integerForKey:@"SyncEventID"];
        if(syncEventID == 0) {
            syncEventID = kFSEventStreamEventIdSinceNow;
        }
        return syncEventID;
    }
    void fsevents_callback(ConstFSEventStreamRef streamRef,
                           void *userData,
                           size_t numEvents,
                           void *eventPaths,
                           const FSEventStreamEventFlags eventFlags[],
                           const FSEventStreamEventId eventIds[]) {
        
        FSEventStreamTool *streamTool = (__bridge FSEventStreamTool *)userData;
        if (!streamTool.callback) {return;}
        NSArray *pathArr = (__bridge NSArray*)eventPaths;
        FSEventStreamEventId lastRenameEventID = 0;
        NSString* lastPath = nil;
        
        for(int i=0; i<numEvents; i++){
            FSEventStreamEventFlags flag = eventFlags[i];
            NSString* currentPath = pathArr[i];
            if(kFSEventStreamEventFlagItemCreated & flag) {
                streamTool.callback(FSEventStreamTypeCreate,currentPath);
            }
            if(kFSEventStreamEventFlagItemRenamed & flag) {
                FSEventStreamEventId currentEventID = eventIds[i];
                if (currentEventID == lastRenameEventID + 1) {
                    // 重命名或者是移动文件
                    streamTool.callback(FSEventStreamTypeMV,currentPath);
                } else {
                    // 其他情况, 例如移动进来一个文件, 移动出去一个文件, 移动文件到回收站
                    if ([[NSFileManager defaultManager] fileExistsAtPath:currentPath]) {
                        // 移动进来一个文件
                        streamTool.callback(FSEventStreamTypeMoveIn,currentPath);
                    } else {
                        // 移出一个文件
                        streamTool.callback(FSEventStreamTypeMoveOut,currentPath);
                    }
                }
                lastRenameEventID = currentEventID;
                lastPath = currentPath;
            }
            if(kFSEventStreamEventFlagItemRemoved & flag) {
                streamTool.callback(FSEventStreamTypeRemove,currentPath);
            }
            if(kFSEventStreamEventFlagItemModified & flag) {
                streamTool.callback(FSEventStreamTypeModify,currentPath);
            }
        }
        [streamTool updateEventID];
    }
    @end
    
    使用方法
        self.tool = [FSEventStreamTool monitorFileWithPaths:@[@"/Users/xxx/Desktop/macOS/"] callback:^(FSEventStreamType type, NSString *path) {
            NSLog(@"变化类型:%ld 变化的文件路径%@",type,path);
        }];
    

    相关文章

      网友评论

          本文标题:macOS 监听文件夹里文件的状态

          本文链接:https://www.haomeiwen.com/subject/icwfrdtx.html