2017-04-17 73 views
0

该应用程序将数据保存在很多不同的类别中,每个类别都有自己的数据库。 当你在类别之间切换时,你关闭/打开一个新的数据库。iOS 10.3无法打开sqlite db

问题: 这些数据库中的一些无法通过sqlite打开,其他数据库使用完全相同的代码按预期工作。

此外,最新更新(iOS 10.3)后,此问题开始。

获取文件路径:

-(NSString *) filePath { 
    NSString *appGroupId = @"xxx.xxx.extension"; 
    NSURL *appGroupDirectoryPath = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupId]; 
    NSURL *dataBaseURL = [appGroupDirectoryPath URLByAppendingPathComponent:_detailItem]; 
    NSString *paths = dataBaseURL.path; 
return paths; 
} 

打开DB:

-(void)openDB { 
    if (sqlite3_open([[self filePath] UTF8String], &db) != SQLITE_OK) { 
     sqlite3_close(db); 
     NSLog(@"error"); 
    } 
    else{ 
     NSLog(@"Opened"); 
    } 
} 

所有DB的都使用此代码打开,唯一的区别是文件名。 大多数文件名都包含特殊字符,如åäö。

Filenames/DB Names: 
ma värd 
ga väg A4 

-这些文件存在于同一个文件夹中。

两个文件都包含数据,有些列甚至完全相同。

导向轴用相同的代码创建

当试图访问第一个我得到一个空数据库文件,所有SELECT语句返回“没有这样的表:表格名”

当试图访问第二一,一切都按预期工作。

之一,是许多SELECT语句:

-(NSString *)antalAsString:(NSString *)typAvAntal { 

    NSString *antalMatt = [[NSString alloc] init]; 
    NSString *sql = [NSString stringWithFormat:@"SELECT sum(antal) FROM '%@'", typAvAntal]; 
    sqlite3_stmt *statement; 
    NSLog(@"sql string: %@", sql); 

    const char *err; 
    if(sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, &err)==SQLITE_OK) 
    { 
     while (sqlite3_step(statement)==SQLITE_ROW) { 
      char *antal = (char *) sqlite3_column_text(statement, 0); 
      if (antal != NULL) { 
       antalMatt = [[NSString alloc]initWithUTF8String:antal]; 

       //.... 


       } 
      } 

     } 

    else { 
     NSLog(@"error: %s", sqlite3_errmsg(db)); 
    } 

    sqlite3_finalize(statement); 

    return antalMatt; 
} 

这怎么可能?在iOS 10.3中,sqlite有什么改变?

编辑/ UPDATE:

在文件夹中的每个文件都怀着的NSArray/NSLog的,看到含有特殊字符的文件名每次都被复制成另一种格式。

这2个文件:

Filenames/DB Names: 
ma värd 
ga väg A4 

都成了这4个文件:

ma va\U0308rd 
ma v\U00e4rd 

ga va\U0308g A4 
ga v\U00e4g A4 

当我尝试检查的文件大小 “马VA \ U0308rd”,将字符串转换成“马värd“,所以我不知道哪两个被引用。

NSString *sourcePath = [self filePath]; 

NSFileManager *fm = [NSFileManager defaultManager]; 
NSError *Error = nil; 
NSArray *sourceFiles = [fm contentsOfDirectoryAtPath:sourcePath error:&Error]; 
int i = 0; 
for (NSString *currentFile in sourceFiles) 
{ 
    if ([fm fileExistsAtPath:[sourcePath stringByAppendingPathComponent:[sourceFiles objectAtIndex:i]]]) 
    { 
     if ([currentFile hasPrefix:@"ma"]) 
     { 

     unsigned long long fileSize = [[fm attributesOfItemAtPath:[sourcePath stringByAppendingPathComponent:[sourceFiles objectAtIndex:i]] error:nil] fileSize]; 

      NSLog(@"FILE: %@ _______ SIZE: %llu", [sourceFiles objectAtIndex:i], fileSize); 
     } 
    } 
    else { 
     NSLog(@"NO FILE EXISTS: %@", currentFile); 

    } 
    i = i+1; 
} 

了很多问题:

为什么更新创建副本?

哪一个文件管理器选择?

Sqlite会选择哪一个?

有没有办法将“ma va \ U0308rd”声明为NSString而没有将其转换为“mavärd”?

帮助表示赞赏。

+0

最有可能是因为[有源电力滤波器(https://9to5mac.com/2017/03/21/what-is-apples-upcoming-apfs-apple-file-system-and-what-it -means-to-you /)在iOS 10.3中引入 – phi

+0

是的,您可能是对的,这些文件似乎完全无法到达,无法备份。将不得不删除所有数据丢失的整个文件夹 – Niklas

回答

0

我不知道为什么更新会创建应用程序组文件夹中每个文件的重复项。 但了解到有一种方法可以控制使用特殊字符的unicode表单。看起来,如果没有指定,系统会随机挑选一个,或者选择找到的第一个文件,而不管哪个表单有。

苹果文档:

> decomposedStringWithCanonicalMapping A string made by normalizing the 
> string’s contents using the Unicode Normalization Form D. 
> 
> decomposedStringWithCompatibilityMapping A string made by normalizing 
> the receiver’s contents using the Unicode Normalization Form KD. 
> 
> precomposedStringWithCanonicalMapping A string made by normalizing the 
> string’s contents using the Unicode Normalization Form C. 
> 
> precomposedStringWithCompatibilityMapping A string made by normalizing 
> the receiver’s contents using the Unicode Normalization Form KC. 

分解 - 使用的字符序列(A + \ U0308 = A)

预组成 - 使用唯一码的每个字符(\ U00e4 = A)

能够通过在所有数据之间进行切换来保存所有数据,以便访问真实的数据库文件并删除已创建的“傻瓜”。

-(NSString *) filePath { 
     NSString *appGroupId = @"xxx.xxx.extension"; 
     NSURL *appGroupDirectoryPath = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupId]; 
     NSURL *dataBaseURL = [appGroupDirectoryPath URLByAppendingPathComponent:_detailItem]; 
     NSString *paths = dataBaseURL.path.decomposedStringWithCompatibilityMapping; 

    return paths; 
    }