我有以下问题:我通过SSZipArchive(在Swift应用程序中)提取了一个zip文件,并且有一些文件名带有“无效”字符。
我认为原因是我在Windows下压缩文件,因此名称现在用ANSI编码。
有没有办法在解压缩过程中转换所有“损坏的”文件夹和文件名? 还是以后?如果我必须迭代文件夹树并重命名文件,那将是没有问题的 但我不知道如何找出ANSI中设置的名称,我也不知道如何纠正字符集。
答案 0 :(得分:0)
可能在最新的SSZipArchive(目前为2.1.1)中修复。我已经以类似于下面代码的方式实现了对非Unicode文件名的支持,因此您可以根据需要重复使用它来自己处理文件名。
好吧,它在Objective-C中,但由于SSZipArchive已经有了解决方案,你不再需要它了。否则,要么建立一个桥接头,将objective-c代码包含在swift应用程序中,或者将其转换为Swift(应该很容易)。
@implementation NSString (SSZipArchive)
+ (NSString *)filenameStringWithCString:(const char *)filename size:(uint16_t)size_filename
{
// unicode conversion attempt
NSString *strPath = @(filename);
if (strPath) {
return strPath;
}
// if filename is non-unicode, detect and transform Encoding
NSData *data = [NSData dataWithBytes:(const void *)filename length:sizeof(unsigned char) * size_filename];
// supported encodings are in [NSString availableStringEncodings]
[NSString stringEncodingForData:data encodingOptions:nil convertedString:&strPath usedLossyConversion:nil];
if (strPath) {
return strPath;
}
// if filename encoding is non-detected, we default to something based on data
// note: hexString is more readable than base64RFC4648 for debugging unknown encodings
strPath = [data hexString];
return strPath;
}
@end
@implementation NSData (SSZipArchive)
// initWithBytesNoCopy from NSProgrammer, Jan 25 '12: https://stackoverflow.com/a/9009321/1033581
// hexChars from Peter, Aug 19 '14: https://stackoverflow.com/a/25378464/1033581
// not implemented as too lengthy: a potential mapping improvement from Moose, Nov 3 '15: https://stackoverflow.com/a/33501154/1033581
- (NSString *)hexString
{
const char *hexChars = "0123456789ABCDEF";
NSUInteger length = self.length;
const unsigned char *bytes = self.bytes;
char *chars = malloc(length * 2);
// TODO: check for NULL
char *s = chars;
NSUInteger i = length;
while (i--) {
*s++ = hexChars[*bytes >> 4];
*s++ = hexChars[*bytes & 0xF];
bytes++;
}
NSString *str = [[NSString alloc] initWithBytesNoCopy:chars
length:length * 2
encoding:NSASCIIStringEncoding
freeWhenDone:YES];
return str;
}
@end
答案 1 :(得分:0)
official spec表示路径应该在代码页中编码,如果设置了通用字段的第11位:
D.1 ZIP格式历来只支持原始的IBM PC 字符编码集,通常称为IBM Code Page 437。 这会将文件名字符存储限制为仅限于 原始MS-DOS范围的值并没有正确支持文件 其他字符编码或语言中的名称。解决这个问题 限制,本规范将支持以下更改。
D.2如果未设置通用位11,则为文件名和注释 应符合原始的ZIP字符编码。如果一般 目的位11设置,文件名和注释必须支持 使用该字符的Unicode标准版本4.1.0或更高版本 由UTF-8存储规范定义的编码形式。该 Unicode标准由The Unicode Consortium发布 (www.unicode.org)。存储在ZIP文件中的UTF-8编码数据是 预计不包括字节顺序标记(BOM)。
我最近发布了名为ZIPFoundation的ZIP文件格式的Swift开源实现。它符合标准,应该能够检测Windows路径名并正确解码它们。