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

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

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

原来,没在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 = [super init];

    delegate = NULL;

    

    dirFD = -1;

    kq = -1;

    dirKQRef = NULL;

    

    return self;

}

- (void)dealloc

{

    [self invalidate];

}

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

{

    DirectoryWatcher *retVal = NULL;

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

    {

        DirectoryWatcher *tempManager = [[DirectoryWatcher alloc] init];

        tempManager.delegate = watchDelegate;

        if ([tempManager startMonitoringDirectory: 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);

    

    struct kevent   event;

    struct timespec 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

    [delegate directoryDidChange:self];

    

    CFFileDescriptorEnableCallBacks(dirKQRef, kCFFileDescriptorReadCallBack);

}

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

{

    DirectoryWatcher *obj;

    

    obj = (__bridge DirectoryWatcher *)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)

            {

                struct kevent 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, (__bridge void *)(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

                            return YES;

                        }

                        // 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;

        }

    }

    return NO;

}

@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 = [[NSMutableArray alloc] init];

    

    NSString *documentsDirectoryPath = [self applicationDocumentsDirectory];

    

    NSArray *documentsDirectoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectoryPath

                                                                                              error:NULL];

    

    for (NSString* curFileName in [documentsDirectoryContents objectEnumerator]) {

        //

        NSString *filePath = [documentsDirectoryPath stringByAppendingPathComponent:curFileName];

        //

        BOOL isDirectory;

        [[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDirectory];

        

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

        if (!isDirectory)

        {

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

            [dirArray addObject:curFileName];

        }

    }

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

    [fileTableView reloadData];

}

#pragma mark -

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

viewDidLoad中加入相关代码

- (void)viewDidLoad {

    [super viewDidLoad];

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

    

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

    // start monitoring the document directory…

    docWatcher = [DirectoryWatcher watchFolderWithPath:[self applicationDocumentsDirectory] delegate:self];

    // scan for existing documents

    [self directoryDidChange: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 [dirArray count];

}

//设置cell的显示

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

    //

    static NSString *SimpleTableIdentifier = @"SimpleTableIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SimpleTableIdentifier];

    if (cell == nil) {

        cell = [[UITableViewCell alloc]

                initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:SimpleTableIdentifier];

    }

    

    NSUInteger row = [indexPath row];

    NSString *str = [dirArray objectAtIndex:row];

    cell.textLabel.text = str;

    

    return cell;

}

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

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

         NSString *str = [dirArray objectAtIndex:[indexPath row]];

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

        

     NSData *reader = [NSData dataWithContentsOfFile:path];

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

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值