背景
最近开发辞书软件的时发现离线包音频无法在iOS 10.3进行播放,经过调查发现是iOS 10.3使用了苹果的新文件系统APFS,而APFS不支持大部分的非英文字符类似(zi? ca?n xi?ng hui?)。导致SSZipArchive无法解压出带音标的文件。而在整个解压过程中程序没有任何异常。最后确定问题是iOS 10.3 使用的APFS系统上fopen()无法打开带音标的文件名,且整个过程没有任何错误信息和异常警告。
官方介绍
APFS is currently unusable with most non-English languages。
The time had come to test out my fears over problems with file and folder names inApple’s new filing system, APFS. The TL;DR is that APFS is not currently safeto use with names which might have Unicode normalisation issues – which meansit is only safe with a limited ASCII character set, as shown in the bizarrescreen shot above.
解决方案
当出现使用fopen()的时候如果当前文件是存在特殊字符时,先使用NSFileManager修改当前文件名,使用CFStringConvertEncodingToNSStringEncoding将当前文件名通过kCFStringEncodingGB_18030_2000进行文件重命名。在fopen()进行操作后再使用NSFileManager进行重命名还原。
解决代码参考
1 - (void) testFOpen:(NSString*)fullPath { 2 //start 3 FILE *fp = fopen((const char*)[fullPath UTF8String], "wb"); 4 NSString *tmpFullPath = nil; 5 //判断文件是否创建,没有使用临时文件名处理 6 if (![[NSFileManager defaultManager] fileExistsAtPath:fullPath]) { 7 fclose(fp); 8 //使用临时文件名处理 9 NSString *dir = [fullPath stringByDeletingLastPathComponent]; 10 NSString *tmpFileName = [fullPath lastPathComponent]; 11 NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000); 12 tmpFileName = [NSString stringWithCString:[tmpFileName UTF8String] encoding:enc]; 13 tmpFullPath = [dir stringByAppendingPathComponent:tmpFileName]; 14 fp = fopen((const char*)[tmpFullPath UTF8String], "wb"); 15 } 16 //fp todo 17 //... 18 19 //end 20 fclose(fp); 21 if (tmpFullPath && [[NSFileManager defaultManager] fileExistsAtPath:tmpFullPath]) { 22 //使用重命名还原 23 [[NSFileManager defaultManager] moveItemAtPath:tmpFullPath toPath:fullPath error:nil]; 24 } 25 if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath]) { 26 NSLog(@"file exist"); 27 } 28 }
参考资料
https://eclecticlight.co/2017/04/06/apfs-is-currently-unusable-with-most-non-english-languages/