如何读取IOS共享目录的文件

来源:互联网 发布:php 字符串查找函数 编辑:程序博客网 时间:2024/05/20 09:09

最近开发了桥牌PBN、围棋SGF、国际和中国象棋PGN等文件在iMac电脑上的阅读软件,想转换到IOS版本,这些文件可以通过 iTunes 的 file sharing 功能将文件导入到iPhone/iPad中的App中,前提是你的App在开发时,将info.plist文件中的Application supports iTunes file sharing 设置为Yes。


通过 iTunes将文件导入到你的应用中,操作比较简单,打开 iTunes,连接你的iPhone/iPad,选择你的设备,找到你要导入文件的应用,比如我的Chess PGN Viewer,然后,点击添加,就可以将PGN文件导入到Chess PGN Viewer的共享文件夹,这样,就可以用Chess PGN Viewer打开这些文件了。


原来,没在IOS上做过这种功能,搜索IOS共享文件的读取,有几个例子,按一个简单的例子做好,提交到AppStore,审核被拒绝!原因是审核人员在导入文件后,无法看到导入的文件,就以功能缺陷为由拒绝了。我的App当时确实不能及时显示导入的文件,而是需要自己刷新一下,才能显示。但审核人员认为应该在导入后应可以立即显示出文件列表。


审核被拒绝后,又搜索了一下,按例子做了一个实时监控文件变化的,功能确实是可以实现的,但延迟时间比较长,有时候需要好几秒钟才能显示出文件列表来,不可忍受。最后,找到了苹果公司官方的例子,DirectoryWatcher,经测试效果非常好,一旦文件导入,立即就能显示。引入DirectoryWatcher后,提交Appstore,审核通过。代码比较简单,全部代码如下:


DirectoryWatcher.h 


#import <Foundation/Foundation.h>


@class DirectoryWatcher;


@protocol DirectoryWatcherDelegate <NSObject>

@required

- (void)directoryDidChange:(DirectoryWatcher *)folderWatcher;

@end


@interface DirectoryWatcher : NSObject

{

    id <DirectoryWatcherDelegate>__weak delegate;

    

    int dirFD;

    int kq;

    

    CFFileDescriptorRef dirKQRef;

}

@property (nonatomic,weak) id <DirectoryWatcherDelegate> delegate;


+ (DirectoryWatcher *)watchFolderWithPath:(NSString *)watchPath delegate:(id<DirectoryWatcherDelegate>)watchDelegate;

- (void)invalidate;

@end



DirectoryWatcher.m


#import "DirectoryWatcher.h"


#include <sys/types.h>

#include <sys/event.h>

#include <sys/time.h>

#include <fcntl.h>

#include <unistd.h>


#import <CoreFoundation/CoreFoundation.h>


@interface DirectoryWatcher (DirectoryWatcherPrivate)

- (BOOL)startMonitoringDirectory:(NSString *)dirPath;

- (void)kqueueFired;

@end



#pragma mark -


@implementation DirectoryWatcher


@synthesize delegate;


- (instancetype)init

{

    self = [superinit];

    delegate =NULL;

    

    dirFD = -1;

    kq = -1;

    dirKQRef =NULL;

    

    returnself;

}


- (void)dealloc

{

    [selfinvalidate];

}


+ (DirectoryWatcher *)watchFolderWithPath:(NSString *)watchPath delegate:(id)watchDelegate

{

    DirectoryWatcher *retVal =NULL;

    if ((watchDelegate !=NULL) && (watchPath != NULL))

    {

        DirectoryWatcher *tempManager = [[DirectoryWatcheralloc] init];

        tempManager.delegate = watchDelegate;

        if ([tempManagerstartMonitoringDirectory: watchPath])

        {

            // Everything appears to be in order, so return the DirectoryWatcher.

            // Otherwise we'll fall through and return NULL.

            retVal = tempManager;

        }

    }

    return retVal;

}


- (void)invalidate

{

    if (dirKQRef !=NULL)

    {

        CFFileDescriptorInvalidate(dirKQRef);

        CFRelease(dirKQRef);

        dirKQRef =NULL;

        // We don't need to close the kq, CFFileDescriptorInvalidate closed it instead.

        // Change the value so no one thinks it's still live.

        kq = -1;

    }

    

    if(dirFD != -1)

    {

        close(dirFD);

        dirFD = -1;

    }

}


@end



#pragma mark -


@implementation DirectoryWatcher (DirectoryWatcherPrivate)


- (void)kqueueFired

{

    assert(kq >=0);

    

    structkevent   event;

    structtimespec timeout = {0,0};

    int             eventCount;

    

    eventCount = kevent(kq,NULL, 0, &event,1, &timeout);

    assert((eventCount >=0) && (eventCount < 2));

    

    // call our delegate of the directory change

    [delegatedirectoryDidChange:self];

    

    CFFileDescriptorEnableCallBacks(dirKQRef,kCFFileDescriptorReadCallBack);

}


static void KQCallback(CFFileDescriptorRef kqRef,CFOptionFlags callBackTypes,void *info)

{

    DirectoryWatcher *obj;

    

    obj = (__bridgeDirectoryWatcher *)info;

    assert([obj isKindOfClass:[DirectoryWatcher class]]);

    assert(kqRef == obj->dirKQRef);

    assert(callBackTypes == kCFFileDescriptorReadCallBack);

    

    [obj kqueueFired];

}


- (BOOL)startMonitoringDirectory:(NSString *)dirPath

{

    // Double initializing is not going to work...

    if ((dirKQRef ==NULL) && (dirFD == -1) && (kq == -1))

    {

        // Open the directory we're going to watch

        dirFD =open([dirPath fileSystemRepresentation],O_EVTONLY);

        if (dirFD >=0)

        {

            // Create a kqueue for our event messages...

            kq =kqueue();

            if (kq >=0)

            {

                structkevent eventToAdd;

                eventToAdd.ident  =dirFD;

                eventToAdd.filter =EVFILT_VNODE;

                eventToAdd.flags  =EV_ADD | EV_CLEAR;

                eventToAdd.fflags =NOTE_WRITE;

                eventToAdd.data   =0;

                eventToAdd.udata  =NULL;

                

                int errNum =kevent(kq, &eventToAdd,1, NULL,0, NULL);

                if (errNum ==0)

                {

                    CFFileDescriptorContext context = {0, (__bridgevoid *)(self),NULL, NULL,NULL };

                    CFRunLoopSourceRef      rls;

                    

                    // Passing true in the third argument so CFFileDescriptorInvalidate will close kq.

                    dirKQRef =CFFileDescriptorCreate(NULL,kq, true,KQCallback, &context);

                    if (dirKQRef !=NULL)

                    {

                        rls = CFFileDescriptorCreateRunLoopSource(NULL,dirKQRef, 0);

                        if (rls !=NULL)

                        {

                            CFRunLoopAddSource(CFRunLoopGetCurrent(), rls,kCFRunLoopDefaultMode);

                            CFRelease(rls);

                            CFFileDescriptorEnableCallBacks(dirKQRef,kCFFileDescriptorReadCallBack);

                            

                            // If everything worked, return early and bypass shutting things down

                            returnYES;

                        }

                        // Couldn't create a runloop source, invalidate and release the CFFileDescriptorRef

                        CFFileDescriptorInvalidate(dirKQRef);

                        CFRelease(dirKQRef);

                        dirKQRef =NULL;

                    }

                }

                // kq is active, but something failed, close the handle...

                close(kq);

                kq = -1;

            }

            // file handle is open, but something failed, close the handle...

            close(dirFD);

            dirFD = -1;

        }

    }

    returnNO;

}


@end



将DirectoryWatcher.h和DirectoryWatcher.m导入到你的工程中。


在myViewController.h中,添加与读取共享文件夹的变量定义


#import <UIKit/UIKit.h>

#import "DirectoryWatcher.h"


@interface myViewController : UIViewController <DirectoryWatcherDelegate> {


//显示文件列表

IBOutlet UITableView *fileTableView;


//存储沙盒子里的所有文件

NSMutableArray *dirArray;


//苹果的方法

DirectoryWatcher *docWatcher;


}


@end



在myViewController.m中,实现读取共享文件清单


#pragma mark -

#pragma mark 文件变动监听方法


- (NSString *)applicationDocumentsDirectory {

    //

    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) lastObject];

}


- (void)directoryDidChange:(DirectoryWatcher *)folderWatcher {

    //

    dirArray = [[NSMutableArrayalloc] init];

    

    NSString *documentsDirectoryPath = [selfapplicationDocumentsDirectory];

    

    NSArray *documentsDirectoryContents = [[NSFileManagerdefaultManager] contentsOfDirectoryAtPath:documentsDirectoryPath

                                                                                             error:NULL];

    

    for (NSString* curFileNamein [documentsDirectoryContentsobjectEnumerator]) {

        //

        NSString *filePath = [documentsDirectoryPathstringByAppendingPathComponent:curFileName];

        //

        BOOL isDirectory;

        [[NSFileManagerdefaultManager] fileExistsAtPath:filePathisDirectory:&isDirectory];

        

        // proceed to add the document URL to our list (ignore the "Inbox" folder)

        if (!isDirectory)

        {

            //这里显示共享文件夹内的所有文件,如果想只显示你的PGN文件,就对curFileName是否是PGN进行判断

            [dirArrayaddObject:curFileName];

        }

    }

    //step6. 刷新列表,显示数据

    [fileTableViewreloadData];

}


#pragma mark -

#pragma mark 文件变动监听方法结束


viewDidLoad中加入相关代码

- (void)viewDidLoad {

    [superviewDidLoad];

    // Do any additional setup after loading the view from its nib.

    

    //苹果监听Document目录的文件改动

    // start monitoring the document directory…

    docWatcher = [DirectoryWatcherwatchFolderWithPath:[selfapplicationDocumentsDirectory]delegate:self];

    // scan for existing documents

    [selfdirectoryDidChange:docWatcher];


    //保存一份txt文件到设备document文件夹中(为了测试方便)

    //NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    //NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory

    //NSString *filePath;

    //char *saves = "test_files";

    //NSData *data = [[NSData alloc] initWithBytes:saves length:10];

    //filePath = [documentsPath stringByAppendingPathComponent:@"test.pgn"];

    //[data writeToFile:filePath atomically:YES];

}


在TableView的代理方法中加入


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    //

    return [dirArraycount];

}


//设置cell的显示

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    //

    staticNSString *SimpleTableIdentifier =@"SimpleTableIdentifier";

    UITableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:SimpleTableIdentifier];

    if (cell ==nil) {

        cell = [[UITableViewCellalloc]

                initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:SimpleTableIdentifier];

    }

    

    NSUInteger row = [indexPathrow];

    NSString *str = [dirArrayobjectAtIndex:row];

    cell.textLabel.text = str;

    

    return cell;

}


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

     //选中某文件,读取文件

         NSString *str = [dirArrayobjectAtIndex:[indexPathrow]];

     NSString *path=[[NSHomeDirectory()stringByAppendingPathComponent:@"Documents"]stringByAppendingPathComponent:str];

        

     NSData *reader = [NSDatadataWithContentsOfFile:path];

     //获得reader后,你想干什么,就是你自己的事了,哈哈。

}