工具作用:
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);
}];
网友评论