将 NSData 转换为 Hex NSString

Posted

技术标签:

【中文标题】将 NSData 转换为 Hex NSString【英文标题】:Convert NSData into Hex NSString 【发布时间】:2012-11-09 11:21:28 【问题描述】:

参考以下问题:Convert NSData into HEX NSString

我已经使用 Erik Aigner 提供的解决方案解决了这个问题:

NSData *data = ...;
NSUInteger capacity = [data length] * 2;
NSMutableString *stringBuffer = [NSMutableString stringWithCapacity:capacity];
const unsigned char *dataBuffer = [data bytes];
NSInteger i;
for (i=0; i<[data length]; ++i) 
  [stringBuffer appendFormat:@"%02X", (NSUInteger)dataBuffer[i]];

但是,有一个小问题,如果后面有多余的零,则字符串值会有所不同。例如。如果六进制数据是字符串@"3700000000000000",当使用扫描仪转换为整数时:

unsigned result = 0;
NSScanner *scanner = [NSScanner scannerWithString:stringBuffer];
[scanner scanHexInt:&result];
NSLog(@"INTEGER: %u",result);

结果将是 4294967295,这是不正确的。不应该是 55,因为只取了 hexa 37?

那么我该如何摆脱零点呢?

编辑:(响应 CRD)

您好,感谢您澄清我的疑问。所以你正在做的是直接从字节指针中读取 64 位整数,对吗?不过我还有一个问题。你实际上如何将 NSData 转换为字节指针?

为了让你更容易理解,我会解释一下我最初是做什么的。

首先,我显示了我拥有的文件的数据(数据是十六进制的)

NSData *file = [NSData dataWithContentsOfFile:@"file path here"];
NSLog(@"Patch File: %@",file);

输出:

接下来,我读取并偏移文件的前 8 个字节,并将它们转换为字符串。

// 0-8 bytes
[file seekToFileOffset:0];
NSData *b = [file readDataOfLength:8];
NSUInteger capacity = [b length] * 2;
NSMutableString *stringBuffer = [NSMutableString stringWithCapacity:capacity];
const unsigned char *dataBuffer = [b bytes];
NSInteger i;
for (i=0; i<[b length]; ++i) 
    [stringBuffer appendFormat:@"%02X", (NSUInteger)dataBuffer[i]];

NSLog(@"0-8 bytes HEXADECIMAL: %@",stringBuffer);

如您所见,0x3700000000000000 是接下来的 8 个字节。为了访问接下来的 8 个字节,我必须做的唯一更改是将 SeekFileToOffset 的值更改为 8,以便访问接下来的 8 个字节的数据。

总而言之,您给我的解决方案很有用,但是手动输入十六进制值是不切实际的。如果将字节格式化为字符串然后解析它们不是这样做的方法,那么我如何直接访问数据的前 8 个字节并将它们转换为字节指针?

【问题讨论】:

这是一个极其缓慢的实现。先格式化成缓冲区,再转换成NSString 【参考方案1】:

您似乎正在尝试将存储在 NSData 中的 8 个字节转换为 64 位整数(0x3700000000000000 中有 8 个字节)。

如果这是您的目标,那么通过将字节格式化为字符串然后解析它们是不是的方法。您需要找出您的数据采用的 endian 格式(即最低或最高有效字节优先),然后使用适当的 endian 转换函数。

顺便说一句,您获得 4294967295 (0xFFFFFFFF) 的原因是因为您要求 NSScanner 读取一个 32 位整数并且您的数字 (0x3700000000000000) 溢出。

回复评论

由于 x86 是 little-endian,您可以通过强制转换直接从字节指针读取 little-endian 64 位整数:

Byte bytes[] =  0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ;
NSLog(@"%lld", *(int64_t *)bytes);

如果您需要读取 big-endian 数据,那么您可以使用 endian 转换函数,例如 Endian64_Swap - 它只会翻转您拥有的数据,因此请先阅读然后翻转。

请注意,x86 并不要求数据访问要对齐,但如果是这样,性能会更好。

【讨论】:

这就是我想要实现的。我之前尝试过使用带有 NSUTF16LittleEndianStringEncoding 的 NSData 初始化字符串,但它给了我 7。但是,在阅读了您的答案并从外部寻求建议后,我意识到这种做法是有缺陷的并且完全错误。关于如何在转换之前找出我的数据的字节序格式的任何想法? @Dawson - 有真正确定字节序格式的已知方法,您可以根据值进行猜测,但您不会真正知道。因此,除非您知道预期值的范围,否则您需要从生成数据的人那里找到答案。 假设数据是小端格式。我可以使用哪些适当的转换函数将 (0x3700000000000000) 转换为 64 位整数,在本例中为 55?据我所知,NSScanner 似乎没有合适的功能。 @Dawson - 我已添加到上面的答案中。 @Dawson - 你基本上已经自己写了答案NSData *fileContents = [NSData dataWithContentsOfFile:@"file path here"]; Byte *ptrToBytes = [fileContents bytes];。现在根据需要转换并增加 ptrToBytes 以处理您的数据。【参考方案2】:

4,294,967,295 是ULONG_MAX,因此扫描仪似乎只是溢出了。 (scanHexInt 方法会吃掉它找到的所有十六进制数字,并且由于零也是一个六进制数字,因此该方法会忽略整个数字,超过 ULONG_MAX。)

【讨论】:

问题似乎出在最高有效位和最低有效位上。如果我使用小端编码,字符串很可能只需要 37 并忽略后面的零。但是我该如何实现呢? 从高层次上看,你真正想要做什么? 我正在尝试将 8 个字节转换为 64 位整数,但我不确定执行此操作的适当方法是什么。看来我实现这一目标的方法是错误的。因此,我正在寻求一些建议。

以上是关于将 NSData 转换为 Hex NSString的主要内容,如果未能解决你的问题,请参考以下文章

将 NSData 转换为 NSString 并再次转换为 NSData?

如何将NSString值转换为NSData?

将 NSData 转换为 NSString 返回 nil

将 NSString 转换为 NSData 是不是会强制使用尾随字节?

将 NSData 转换为 NSString 的空结果

将 UTF-8 编码的 NSData 转换为 NSString