如何将NSData转换为NSStringhexstring?
当我在一个NSData
对象上调用-description
时,我看到一个漂亮的hexstring的NSData
对象的字节,如:
<f6e7cd28 0fc5b5d4 88f8394b af216506 bc1bba86 4d5b483d>
我想这个数据的表示(减去lt / gt引号)到内存中的NSString
所以我可以使用它..我不想调用-[NSData description]
,然后只是修剪lt / gt引号(因为我认为这不是NSData
的公共接口的保证方面,并且在将来会有变化)。
将NSData
对象的这种表示forms转换成NSString
对象(除了调用-description
),最简单的方法是什么?
请记住,任何String(format: ...)
解决scheme将非常慢(对于大数据)
NSData *data = ...; NSUInteger capacity = data.length * 2; NSMutableString *sbuf = [NSMutableString stringWithCapacity:capacity]; const unsigned char *buf = data.bytes; NSInteger i; for (i=0; i<data.length; ++i) { [sbuf appendFormat:@"%02X", (NSUInteger)buf[i]]; }
如果你需要更高性能的东西,试试这个:
static inline char itoh(int i) { if (i > 9) return 'A' + (i - 10); return '0' + i; } NSString * NSDataToHex(NSData *data) { NSUInteger i, len; unsigned char *buf, *bytes; len = data.length; bytes = (unsigned char*)data.bytes; buf = malloc(len*2); for (i=0; i<len; i++) { buf[i*2] = itoh((bytes[i] >> 4) & 0xF); buf[i*2+1] = itoh(bytes[i] & 0xF); } return [[NSString alloc] initWithBytesNoCopy:buf length:len*2 encoding:NSASCIIStringEncoding freeWhenDone:YES]; }
Swift 3版本
extension NSData { var hexString: String? { let buf = bytes.assumingMemoryBound(to: UInt8.self) let charA = UInt8(UnicodeScalar("a").value) let char0 = UInt8(UnicodeScalar("0").value) func itoh(_ value: UInt8) -> UInt8 { return (value > 9) ? (charA + value - 10) : (char0 + value) } let hexLen = length * 2 let ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: hexLen) for i in 0 ..< length { ptr[i*2] = itoh((buf[i] >> 4) & 0xF) ptr[i*2+1] = itoh(buf[i] & 0xF) } return String(bytesNoCopy: ptr, length: hexLen, encoding: .utf8, freeWhenDone: true) } }
我同意解决scheme不要调用的description
是保留debugging,所以好点和好问题:)
最简单的解决scheme是循环通过NSData
的字节,并从中构buildNSString。 使用[yourData bytes]
访问字节,并build立一个NSMutableString
的string。
这是一个使用NSData类实现的例子
@interface NSData(Hex) -(NSString*)hexRepresentationWithSpaces_AS:(BOOL)spaces; @end @implementation NSData(Hex) -(NSString*)hexRepresentationWithSpaces_AS:(BOOL)spaces { const unsigned char* bytes = (const unsigned char*)[self bytes]; NSUInteger nbBytes = [self length]; //If spaces is true, insert a space every this many input bytes (twice this many output characters). static const NSUInteger spaceEveryThisManyBytes = 4UL; //If spaces is true, insert a line-break instead of a space every this many spaces. static const NSUInteger lineBreakEveryThisManySpaces = 4UL; const NSUInteger lineBreakEveryThisManyBytes = spaceEveryThisManyBytes * lineBreakEveryThisManySpaces; NSUInteger strLen = 2*nbBytes + (spaces ? nbBytes/spaceEveryThisManyBytes : 0); NSMutableString* hex = [[NSMutableString alloc] initWithCapacity:strLen]; for(NSUInteger i=0; i<nbBytes; ) { [hex appendFormat:@"%02X", bytes[i]]; //We need to increment here so that the every-n-bytes computations are right. ++i; if (spaces) { if (i % lineBreakEveryThisManyBytes == 0) [hex appendString:@"\n"]; else if (i % spaceEveryThisManyBytes == 0) [hex appendString:@" "]; } } return [hex autorelease]; } @end
用法:
NSData* data = ... NSString* hex = [data hexRepresentationWithSpaces_AS:YES];
我最喜欢@Erik_Aigner的回答。 我只是重构了一下:
NSData *data = [NSMutableData dataWithBytes:"acani" length:5]; NSUInteger dataLength = [data length]; NSMutableString *string = [NSMutableString stringWithCapacity:dataLength*2]; const unsigned char *dataBytes = [data bytes]; for (NSInteger idx = 0; idx < dataLength; ++idx) { [string appendFormat:@"%02x", dataBytes[idx]]; }
只是想补充一点,@PackKits的方法可以使用Swift 3写得非常优雅,因为Data
现在是一个集合。
extension Data { var hex: String { var hexString = "" for byte in self { hexString += String(format: "%02X", byte) } return hexString } }
要么 …
extension Data { var hex: String { return self.map { b in String(format: "%02X", b) }.joined() } }
甚至 …
extension Data { var hex: String { return self.reduce("") { string, byte in string + String(format: "%02X", byte) } } }
在Swift中,你可以创build一个扩展。
extension NSData { func toHexString() -> String { var hexString: String = "" let dataBytes = UnsafePointer<CUnsignedChar>(self.bytes) for (var i: Int=0; i<self.length; ++i) { hexString += String(format: "%02X", dataBytes[i]) } return hexString } }
那么你可以简单地使用:
let keyData: NSData = NSData(bytes: [0x00, 0xFF], length: 2) let hexString = keyData.toHexString() println("\(hexString)") // Outputs 00FF
可悲的是没有内置的方法来从NSData生成hex,但要做到这一点很容易。 简单的方法是将连续的字节传递给sprintf(“%02x”)并将其累加到一个NSMutableString中。 更快的方法是build立一个将4位映射到hex字符的查找表,然后将连续的nybbles传递到该表中。
虽然它可能不是最有效的方法,但是如果你这样做是为了debugging的话,SSCrypto在NSData上有一个类别,它包含两个方法来做到这一点(一个用于创build原始字节值的NSString,显示了一个更漂亮的表示)。
看到在评论中有一个Swift 1.2片段,这里是Swift 2版本,因为C风格的for循环现在已经被弃用了。 按照麻省理工学院的执照和两个简单的unit testing,如果你在乎
以下是您方便的代码:
import Foundation extension NSData { var hexString: String { let pointer = UnsafePointer<UInt8>(bytes) let array = getByteArray(pointer) return array.reduce("") { (result, byte) -> String in result.stringByAppendingString(String(format: "%02x", byte)) } } private func getByteArray(pointer: UnsafePointer<UInt8>) -> [UInt8] { let buffer = UnsafeBufferPointer<UInt8>(start: pointer, count: length) return [UInt8](buffer) } }