无法将 sqlite 文件从应用程序包复制到文档目录:获取(Cocoa 错误 260)

Posted

技术标签:

【中文标题】无法将 sqlite 文件从应用程序包复制到文档目录:获取(Cocoa 错误 260)【英文标题】:Unable to copy sqlite file from app bundle to documents directory: getting (Cocoa error 260) 【发布时间】:2013-07-24 20:36:12 【问题描述】:

我正在尝试使用以下代码将我的 sqlite 文件从 app bundle 复制到文档目录中

-(id)init 

    self = [super init];
    if (self) 

// 1.为UIManagedDocument创建数据库文件句柄

        NSURL *docURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
        docURL = [docURL URLByAppendingPathComponent:@"DefaultDatabase"];
        self.document =  [[UIManagedDocument alloc] initWithFileURL:docURL]; // URL of the location of document i.e. /documents directory
    NSLog(@" URL document");

        //set our document up for automatic migrations

        if (self.document) 
            NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                 [NSNumber numberWithBool:YES],
            NSMigratePersistentStoresAutomaticallyOption,
                                 [NSNumber numberWithBool:YES],
            NSInferMappingModelAutomaticallyOption, nil];

            self.document.persistentStoreOptions = options;

            // Register for Notifications

            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(objectsDidChange:) name:NSManagedObjectContextObjectsDidChangeNotification object:self.document.managedObjectContext];

            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:self.document.managedObjectContext];
         else          
            NSLog(@"The UIManaged Document could not be initialized");

        

// 2. 首次运行时检查持久化存储文件是否不存在

    if (!([[NSFileManager defaultManager] fileExistsAtPath:[self.document.fileURL path]])) 
        NSLog(@" persistent file not found trying to copy from app bbundle");
        NSString *docFileName = [UIManagedDocument persistentStoreName];
        NSString *docFilePath = [[NSBundle mainBundle] pathForResource:docFileName ofType:@"sqlite"];
        **NSLog(@" doc file path = %@", docFilePath);**
        if (docFilePath)  // found the database file in app bundle
            NSLog(@" found file in bundle");
            //Production: Copy from app bundle.
            NSError *error = nil;
            NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
            NSString *copyToPath  = [searchPaths lastObject];
            if([[NSFileManager defaultManager] copyItemAtPath:docFilePath toPath:copyToPath error:&error])
                NSLog(@"File successfully copied");
             else  // if could not locate the file
                [[[UIAlertView alloc]initWithTitle:NSLocalizedString(@"error", nil) message: NSLocalizedString(@"failedcopydb", nil)  delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", nil)  otherButtonTitles:nil] show];
                NSLog(@"Error description-%@ \n", [error localizedDescription]);
                NSLog(@"Error reason-%@", [error localizedFailureReason]);
            
        
    

return self;

a) 我使用数据加载器应用程序创建了 .sqlite 文件,该应用程序使用 UIManagedDcoument 将数据添加到核心数据。 .sqlite 文件在文档目录中生成。

b) 我将 *.sqlite 文件添加到资源文件夹并将其添加到捆绑包中。如果我使用终端检查应用程序包。我在包目录下看到“持久存储”和<app name.momd> 文件。没有扩展名为 .sqlite 的文件

c)但是在我上面的代码中,当我使用代码行检查应用程序包中是否存在文件时,它是成功的。所以文件存在于包中

   NSString *file = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:fileName];

d) 但是当尝试复制时,它会失败并给我(Cocca 错误 206),这意味着它无法在应用程序包中找到 .sqlite 文件。

  if([[NSFileManager defaultManager] copyItemAtPath:file toPath:copyToPath error:&error])

这与我在 app bundle 目录下看不到 .sqlite 文件相反我看到持久性存储和 .momd 文件这一事实一致。

那么我哪里错了?

编辑

这是对我如何生成 mydata.sqlite 文件的说明。

我正在使用 Core Data,并希望在首次向用户启动应用程序时提供一个预先填充的数据库。所以我使用数据加载器应用程序为我创建 .sqlite 文件。我将 UIManagedDocument 用于核心数据。运行应用程序后,我看到在文档目录下创建了一个 mydata.sqlite 目录。目录结构如下

/users//.../documents/mydata.sqlite/storeContent/persistenStore.

所以基本上不是创建文件,而是创建一个扩展名为 .sqlite 的目录,我看到了 persistentStore 文件。因此,当我尝试在构建阶段的目标中复制应用程序包下的资源时,它会添加 persistentStore 而不是 .sqlite 文件。

我的问题所描述的都是正确的,我应该在我的代码中以不同的方式处理它。如果是的话,我应该怎么做才能处理数据存储。

我认为 .sqlite 是一个文件而不是一个目录。请指导

谢谢

【问题讨论】:

.sqlite 文件是目标的成员吗? 是的,我在 Build Phases 选项卡的 Copy Bundle Resources 下看到一个行项目,内容为“persistentStore ..in mydata.sqlite/StoreContent”。 它实际上是一个文件夹/目录吗? 是的 mydata.sqlite 是我在 /users//applications/iPhone Simulator/Library/6.1/....in Terminal 下检查时的目录。它有“StoreContent”目录,下面是“persistenStore”文件。 在步骤 c 你应该做[[NSBundle mainBundle] pathForResource:name ofType:@"sqlite"]。我猜它会返回 nil。 【参考方案1】:

这一行实际上并不检查文件是否存在:

NSString *file = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:fileName];

所做的只是在file 中构建路径。如果要检查是否存在,需要使用[NSFileManager fileExistsAtPath:]。或者你可以重新使用pathForResource:ofType:,当它返回nil时显然是正确的。

您似乎根本没有将文件复制到捆绑包中。这是您的 Xcode 项目配置的问题。

【讨论】:

我编辑了我的问题,其中包含有关如何生成预填充的 .sqlite 的信息。我自己并不清楚为什么 .sqlite 是目录而不是文件。我以为事情就是这样。请让我知道如何使用持久存储作为文件来处理 .sqlite 目录。谢谢 SQLite 不是一个目录,唯一的原因是你有一个最后带有.sqlite 的目录,因为这就是你创建它的方式。 persistenStore 文件是 SQLite 文件,其余的是您通过 UIManagedDocument 创建的内容。 谢谢。我明白了,我假设创建了一个文件。因此,在这种情况下,我可以为 UIManagedDocument 创建的 persistentStore 文件提供自定义名称,因为我需要访问以将其添加到应用程序包,然后才能将其用于我的主应用程序。非常感谢大家..它清除了我的理解。 我认为你做不到。您为 UIManagedDocument 提供整个文档名称,它处理内部细节。如果您想控制 SQLite 文件的名称,请摆脱 UIManagedDocument 并以老式方式设置持久性堆栈。 好的。我将使用 UIManagedDocument 生成的“persistentStore”文件添加到应用程序包中。现在我如何获得persistentStore文件的路径,因为 NSString *docFilePath = [[NSBundle mainBundle] pathForResource:docFileName ofType:@"sqlite"]] 返回 null。你能看看上面的代码我已经更新了代码【参考方案2】:

我在 UIManagedDocument 上阅读了apple documentation,这是我在上面出错的关键点

    未正确处理 UIManagedDocument。初始化托管文档时,您指定 文档位置的 URL。 而不是 文档本身。 如果您需要添加

    您可以通过创建 UIManagedDocument 的子类来执行其他自定义,即 重写 persistentStoreName 以自定义文档文件包内的持久存储文件的名称。

    剪切和粘贴示例代码以正确处理数据文件

您使用 initWithFileURL:; 创建一个托管文档对象如果需要,您可以在使用其托管对象上下文之前配置该文档。通常,您可以设置持久存储选项,如下例所示:

NSURL *docURL = [[self applicationDocumentsDirectory]        URLByAppendingPathComponent:@"FirstDocument"];
 doc = [[UIManagedDocument alloc] initWithFileURL:docURL];

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
 [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
 [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
doc.persistentStoreOptions = options;


**if ([[NSFileManager defaultManager] fileExistsAtPath:[docURL path]]**) 
   [doc openWithCompletionHandler:^(BOOL success)
    if (!success) 
        // Handle the error.
    
    ];
 
  else 
   [self addInitialData];
   [doc saveToURL:docURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success)
      if (!success) 
        // Handle the error.
     
     ];
     

【讨论】:

以上是关于无法将 sqlite 文件从应用程序包复制到文档目录:获取(Cocoa 错误 260)的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 XCode 菜单而不是以编程方式将我的 sqlite 文件从文档目录复制到应用程序包

将 sqlite DB 从收件箱复制到文档目录

将文件夹从主包复制到 iphone 中的文档目录

无法将 SQLite 数据库从资产文件夹复制到设备内存

将多个 SQLite 数据库与 FMDB 进行比较

iOS - 将 sqlite 复制到 CoreData 的捆绑包