2010-01-28 14 views
8

Tôi đang nghe các thay đổi về Thư mục và đĩa trong một dự án Cocoa sử dụng FSEvents. Tôi cần nhận các sự kiện khi thư mục gốc được đổi tên hoặc xóa. Vì vậy, tôi đã thông qua kFSEventStreamCreateFlagWatchRoot khi tạo FSEventStream. Nhưng ngay cả khi tôi xóa hoặc đổi tên thư mục gốc, tôi không nhận được FSEventStreamEventFlags tương ứng. Bất kỳ ý tưởng nào có thể là vấn đề. Tôi đang nghe những thay đổi trong thiết bị được gắn USB. Tôi đã sử dụng cả hai FSEventStreamCreateFSEventStreamCreateRelativeToDevice. Một điều tôi thông báo là khi tôi thử với FSEventStreamCreate tôi nhận được thông báo lỗi sau khi tạo FSEventStream:Cách nghe các thay đổi của hệ thống tập tin MAC - kFSEventStreamCreateFlagWatchRoot

(CarbonCore.framework) FSEventStreamCreate: watch_all_parents:
lỗi khi cố gắng thêm kqueue cho fd 7 (/Volumes/NO NAME; Operation không được hỗ trợ)

Nhưng với FSEventStreamCreateRelativeToDevice không có lỗi nhưng vẫn không nhận được kFSEventStreamEventFlagRootChanged trong cờ sự kiện. Ngoài ra, trong khi tạo bằng cách sử dụng FSEventStreamCreateRelativeToDevice táo nói nếu tôi muốn nghe những thay đổi đường dẫn gốc vượt qua chuỗi emty "". Nhưng tôi không thể nghe những thay đổi đường dẫn gốc bằng cách truyền chuỗi rỗng. Nhưng khi tôi vượt qua "/" nó hoạt động. Nhưng ngay cả đối với "/" Tôi không nhận được bất kỳ FSEventStreamEventFlags thích hợp nào. Tôi đang dán mã ở đây:

-(void) subscribeFileSystemChanges:(NSString*) path 
{ 
    PRINT_FUNCTION_BEGIN; 

    // if already subscribed then unsubscribe 
    if (stream) 
    { 
     FSEventStreamStop(stream); 
     FSEventStreamInvalidate(stream); /* will remove from runloop */ 
     FSEventStreamRelease(stream); 
    } 

    FSEventStreamContext cntxt = {0}; 
    cntxt.info = self; 

    CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void**)&path, 1, NULL); 


    stream = FSEventStreamCreate(NULL, &feCallback, &cntxt, 
           pathsToWatch, kFSEventStreamEventIdSinceNow, 1, 
           kFSEventStreamCreateFlagWatchRoot); 


    FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), 
            kCFRunLoopDefaultMode); 

    FSEventStreamStart(stream); 


} 

Gọi lại chức năng:

static void feCallback(ConstFSEventStreamRef streamRef, void* pClientCallBackInfo, 
         size_t numEvents, void* pEventPaths, const FSEventStreamEventFlags eventFlags[], 
         const FSEventStreamEventId eventIds[]) 

{ 
char** ppPaths = (char**)pEventPaths; int i; 

    for (i = 0; i < numEvents; i++) 
    { 
     NSLog(@"Event Flags %lu Event Id %llu", eventFlags[i], eventIds[i]); 
     NSLog(@"Path changed: %@", 
       [NSString stringWithUTF8String:ppPaths[i]]); 
    }  
} 

Thanks a lot trước.

+0

Tôi không chắc là có gì sai vì tôi chưa từng sử dụng FSEvents. Có nói rằng, nó âm thanh như những gì bạn đang cố gắng để làm có thể được thực hiện tốt hơn bằng cách sử dụng khuôn khổ DiskArbitration. –

Trả lời

3

tôi đã cùng một vấn đề và tôi nghĩ rằng tôi figured it out. Rõ ràng kFSEventStreamCreateFlagWatchRoot chỉ đơn giản là bị vỡ khi sử dụng FSEventStreamCreateRelativeToDevice. Bạn phải sử dụng FSEventStreamCreate. Vì biểu mẫu cũ thích hợp hơn nếu bạn dựa vào id sự kiện lịch sử, bạn có thể cần phải tạo 2 luồng. Ngoài ra, lưu ý rằng có vẻ như bạn không nhận được kEventFlagChangedRoot gửi cho bạn nếu ứng dụng của bạn không chạy, vì vậy, bạn cần phải lập chỉ mục thư mục khi bạn khởi động.

3

Tôi nghĩ rằng thay đổi tên khối lượng không được tính là thay đổi trong hệ thống tệp được báo cáo bởi FSEvents. Hãy nhớ rằng, tên khối lượng chính nó không thực sự tồn tại như một mục hệ thống tập tin. Những cái dưới /Volumes được hệ điều hành nấu chín.

Thay vào đó, nó được che phủ bởi Disk Arbitration.

Mã mẫu ngắn sau. Đầu tiên, xác định các callback

#import <DiskArbitration/DiskArbitration.h> 
void callBack(DADiskRef disk,CFArrayRef keys,void *context) 
{ 
    CFDictionaryRef dict=DADiskCopyDescription(disk); 
    NSString*mountPoint=[(NSDictionary*)dict objectForKey:(NSString*)kDADiskDescriptionVolumePathKey]; 
    NSLog(@"disk at %@:",mountPoint); 
    for(NSString*key in (NSArray*)keys){ 
    NSLog(@"key %@ changed: %@",key,[(NSDictionary*)dict objectForKey:key]);  
    } 
    CFRelease(dict); 
} 

và sau đó cài đặt xử lý như thế này

DASessionRef session=DASessionCreate(NULL); 
DARegisterDiskDescriptionChangedCallback(session, NULL, NULL, callBack, NULL); 
DASessionScheduleWithRunLoop(session, [[NSRunLoop currentRunLoop] getCFRunLoop], kCFRunLoopCommonModes); 
+0

HI Cảm ơn bạn đã trả lời. Nhưng tôi đang tìm kiếm giải pháp với FSEVENTS vì điều thực sự làm phiền tôi là ngay cả khi tôi cung cấp đường dẫn gốc "/" hoặc bất kỳ thư mục con nào và sau đó xóa hoặc đổi tên nó, tôi không nhận được cờ sự kiện thích hợp trong cuộc gọi. Tôi đã dán mã trong câu hỏi. Một câu hỏi khác, tôi lấy thông tin đầy đủ về tính năng Ghi đè đĩa vì tôi không biết tôi nên tìm kiếm hoặc xem phím nào, v.v.Hoặc inshort, nơi nào bạn vây giải thích về kDADiskDescriptionVolumePathKey hoặc kDADiskDescriptionWatchVolumeName. – wantro

+0

Các phím có thể được tìm thấy tại http://developer.apple.com/mac/library/documentation/Darwin/Reference/DiscArbitrationFramework/index.html ... Vâng, bạn biết rằng có một hộp tìm kiếm trong trang web ADC, phải ? Bạn có tìm kiếm hằng số ở đó không? Hãy để tôi suy nghĩ về câu hỏi đầu tiên của bạn. – Yuji

+0

Tôi sao chép và dán mã của bạn và mã hoạt động trên máy của tôi (10.6.2). Bạn có thể đăng thói quen gọi lại của mình không và cách bạn kiểm tra cờ sự kiện được trả về? – Yuji