iOS App将TCP接收的十六进制字符串转.tgz文件损坏问题求助
问题根因
- 现有第一种转换逻辑(HEX转NSString再转NSData)不适用于二进制文件场景:tgz为二进制压缩格式,字节值覆盖0x00-0xFF全范围,超出ASCII、UTF8等文本编码的安全映射区间,强制转NSString会出现字节截断、值错乱,生成文件必然损坏。
- 现有第二种HEX直接转NSData的实现存在逻辑错误:64位iOS系统下
unsigned long类型占8字节,原实现每次调用appendBytes:&wholeByte length:2时,会为每个解析出的单字节额外拼接1个0x00空字节,最终文件长度为正常值的2倍,格式完全破坏。 - 提供的待转换HEX串本身合法:串首
1F8B08为gzip格式标准文件头,符合tgz文件特征,无需调整编码方案,仅需修复HEX转二进制逻辑即可正常生成文件。
修复后的代码实现
替换原有错误的转换方法,调整文件写入逻辑:
// 正确的HEX字符串转二进制NSData方法 + (NSData *)dataFromHexString:(NSString *)hexString { // 预处理:过滤TCP传输可能带入的空格、换行等非十六进制字符 NSCharacterSet *hexChars = [NSCharacterSet characterSetWithCharactersInString:@"0123456789abcdefABCDEF"]; NSString *cleanHex = [[hexString componentsSeparatedByCharactersInSet:hexChars.invertedSet] componentsJoinedByString:@""]; NSUInteger len = cleanHex.length; // 奇数长度补前导0做字节对齐 if (len % 2 != 0) { cleanHex = [@"0" stringByAppendingString:cleanHex]; len += 1; } NSMutableData *resultData = [NSMutableData dataWithCapacity:len/2]; const char *cStr = [cleanHex cStringUsingEncoding:NSASCIIStringEncoding]; for (NSUInteger i = 0; i < len; i += 2) { // 用uint8_t单字节类型存储解析结果,避免多字节类型写入冗余数据 uint8_t byte = (uint8_t)(strtoul((char[]){cStr[i], cStr[i+1], '\0'}, NULL, 16) & 0xFF); [resultData appendBytes:&byte length:1]; } return [resultData copy]; } // 修复后的tgz文件写入方法 + (void)writeToLogFile:(NSString*)hexContent fileName:(NSString*)fileNameString{ // 使用苹果官方推荐的沙盒路径获取方式,避免硬编码路径拼接的兼容性问题 NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSString *filePath = [documentsDirectory stringByAppendingPathComponent:fileNameString]; // 直接通过HEX转二进制得到tgz数据,不经过NSString文本类型中转 NSData *tgzData = [self dataFromHexString:hexContent]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ NSError *error = nil; [tgzData writeToFile:filePath options:NSDataWritingAtomic error:&error]; if (error) { NSLog(@"tgz文件写入失败: %@", error.localizedDescription); } else { // 写入完成后校验gzip文件魔数,快速确认格式正确性 NSData *headerCheck = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:nil]; const uint8_t *bytes = headerCheck.bytes; if (headerCheck.length >=2 && bytes[0] == 0x1F && bytes[1] == 0x8B) { NSLog(@"tgz文件写入成功,格式头校验通过"); } } }); }
注意事项
- 所有二进制文件(压缩包、图片、音视频等)的HEX转存操作,都要直接生成
NSData类型,禁止通过NSString做中间编码转换,否则必然出现字节损坏。 - 上述代码完全兼容Xcode 13.1、iOS 15.1+的开发环境,无需额外适配。用提供的测试HEX串转换后,生成的文件可正常解压使用。
内容的提问来源于stack exchange,提问作者madhav kure
相关产品推荐
相关产品推荐

