该应用程序将数据保存在许多不同的类别中,每个类别都有自己的数据库。 当您在类别之间切换时,您关闭/打开一个新的数据库。
问题: 其中一些数据库无法通过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;
}
打开数据库:
-(void)openDB {
if (sqlite3_open([[self filePath] UTF8String], &db) != SQLITE_OK) {
sqlite3_close(db);
NSLog(@"error");
}
else{
NSLog(@"Opened");
}
}
使用此代码打开所有数据库,区别仅在于文件名。 大多数文件名都包含特殊字符,例如åäö。
Filenames/DB Names:
ma värd
ga väg A4
- 这些文件存在于同一文件夹中。
- 两个文件都包含数据,有些列甚至相同。
-Both使用相同的代码
创建当尝试访问第一个时,我得到一个空DB文件,所有SELECT语句都返回“no such table:table_name”
当尝试访问第二个时,一切都按预期工作。
许多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中的某些内容是否有所改变?
EDIT / 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
当我尝试检查“ma va \ U0308rd”的文件大小时,字符串被转换为“mavä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 :(得分:0)
我不知道为什么更新会创建应用程序组文件夹中每个文件的副本。 但是了解到有一种方法可以控制哪个unicode表单与特殊字符一起使用。似乎如果没有指定,系统要么随机选择一个,要么选择它找到的第一个文件,无论哪种形式有。
Apple文档:
> 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 =ä)
precomposed - 为每个字符使用唯一代码(\ U00e4 =ä)
能够通过在这些数据之间切换来保存所有数据,以访问真实的db文件并删除已创建的“假人”。
-(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;
}