应用程序变为活动状态时,文件已加密或不是数据库消息

时间:2014-03-24 12:16:46

标签: ios iphone objective-c sqlite

我有随机案例无法从我的iPad应用程序访问sqlite数据库。我已经使用FMDatabase访问sqlite数据库,我没有在My Provisioning配置文件中启用DataProtection。而且sqlite版本是3.这适用于启用密码的设备。当我的应用程序处于前台时设备进入睡眠状态时,当用户输入密码时,此错误会随机出现。一旦用户成功输入密码,我的应用程序就会出现前景,突然数据库无法访问sqlite代码26:文件已加密或不是数据库

有人可以帮助我解决这个问题。

我添加了一个地方

-(NSString*)getValueForSetting:(NSString*)settingName{
    __block NSString *settingValue ;
    NSString *sql = [NSString stringWithFormat:@"SELECT SettingValue FROM Settings where SettingName = '%@' ",settingName];
    FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:[DatabaseUtility getDBPath]];
    @try{
        [queue inDatabase:^(FMDatabase *database) {
            FMResultSet *results = [database executeQuery:sql];
            if (![database hadError]) {
                if([results next]){
                    settingValue = [results stringForColumn:@"SettingValue"];
                }
            }
            else
            {
                NSLog(@"Database error,get setting value %d: %@", [database lastErrorCode], [database lastErrorMessage]);
            }
            [results close];
        }];
    }
    @catch(NSException *exception){
        NSLog(@"0002,ERR,MemberDataAccess,getiPadDisplayName:(NSString*)memberID, %@",[exception description]);
    }
    @finally {
        [queue close];
    }

    return settingValue;
}

在这里我得到了以下输出

Database error,get setting value 26: file is encrypted or is not a database

编辑1:

我能够隔离出现代码片段的问题。在applicationDidBecomeActive:方法中 我正在调用以下方法。此方法用于将NSLog重定向到文件。

-(void) redirectConsoleLogToDocumentFolder
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                                                         NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];

    NSString *customPath=[documentsDirectory stringByAppendingPathComponent:@"LogFiles"];

    NSFileManager *manager=[NSFileManager defaultManager];
    if (![manager fileExistsAtPath:customPath])  
        [manager createDirectoryAtPath: customPath withIntermediateDirectories:YES attributes:nil error:nil];

    NSLog(@" DeviceLogs Class : custom path: %@",customPath);

    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:@"yyyy-MM-dd"];
    [GlobalSettingsSingelton setLocale:&dateFormat];
    NSDate *today = [NSDate date];

    NSString *todaysDate = [[NSString alloc]initWithFormat:@"%@",[dateFormat stringFromDate:today]];
    NSString *logFile = [[NSString alloc]initWithFormat:@"Log_%@.txt",todaysDate];
    NSString *logPath = [customPath
                         stringByAppendingPathComponent:logFile];

    freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
}

有些时候,在调用此方法后,我的数据库文件会损坏或加密,并在尝试访问数据库时出现上述错误。如果我评论这一行应用程序没有问题。

为了隔离问题,我在freopen()之前和之后调用了两个db访问方法。我在该方法之后添加的数据库访问方法会导致file is encrypted or is not a database错误,而之前的数据库访问方法在没有该问题的情况下运行。

我无法想象这个问题,因为NSLog重定向与DB文件无关。它是如何加密或损坏的。请有人解释一下。

2 个答案:

答案 0 :(得分:1)

您好我终于找到了原因。第一篇this文章帮助我了解sqlite应用程序损坏的线索。它表明我怀疑的一个原因与我的问题有关。

We have seen cases where a file descriptor was open on a log file, then that file descriptor was
 closed and reopened on an SQLite database. Later, some other thread continued to write log 
information into the old file descriptor, not realizing that the log file had been closed already.
 But because the file descriptor had been reopened by SQLite, the information that was intended to 
go into the log file ended up overwriting parts of the SQLite database, leading to corruption of the 
database.

通过编写示例应用程序,我能够重新创建此问题。为此,我使用了两个线程。一个线程使用计时器连续调用redirectConsoleLogToDocumentFolder方法。其他线程用于在循环中运行一些sql查询并添加一些NSLog条目。一段时间后,我收到了file is encrypted or is not a database错误消息。

作为修复,我在redirectConsoleLogToDocumentFolder方法中删除了applicationDidBecomeActive:方法调用,并将其保留在didFinishLaunchingWithOptions:方法中,以保证修复由于以下原因。

  1. 当应用开始运行时,日志文件已经关闭。
  2. 只有一个线程处于活动状态(主线程是主线程)。
  3. 日志文件打开是顺序进程。

答案 1 :(得分:0)

看到这个问题的几个原因, 可能是您的应用程序试图打开数据库两次或多次,以便一个线程被另一个线程阻塞。请检查是否有其他地方尝试同时打开同一个数据库实例。 此外,DB文件可能已经以某种方式损坏,当您在调试时覆盖应用程序时会发生这种情况。只需删除应用程序,重启手机即可。 无论如何,你认为使用Core Data而不是直接处理数据库更好吗?这是你的要求吗?