将NSData字节转换为NSString?

我正在尝试使用BEncoding ObjC类来解码.torrent文件。

 NSData *rawdata = [NSData dataWithContentsOfFile:@"/path/to/the.torrent"]; NSData *torrent = [BEncoding objectFromEncodedData:rawdata]; 

当我NSLog torrent我得到以下内容:

 { announce = <68747470 3a2f2f74 6f727265 6e742e75 62756e74 752e636f 6d3a3639 36392f61 6e6e6f75 6e6365>; comment = <5562756e 74752043 44207265 6c656173 65732e75 62756e74 752e636f 6d>; "creation date" = 1225365524; info = { length = 732766208; name = <7562756e 74752d38 2e31302d 6465736b 746f702d 69333836 2e69736f>; "piece length" = 524288; .... 

如何将name转换为NSString? 我努力了..

 NSData *info = [torrent valueForKey:@"info"]; NSData *name = [info valueForKey:@"name"]; unsigned char aBuffer[[name length]]; [name getBytes:aBuffer length:[name length]]; NSLog(@"File name: %s", aBuffer); 

..回顾数据,但似乎有额外的unicode垃圾:

 File name: ubuntu-8.10-desktop-i386.iso) 

我也试过( 从这里 )..

 NSString *secondtry = [NSString stringWithCharacters:[name bytes] length:[name length] / sizeof(unichar)]; 

..但是这似乎返回一堆随机字符:

 扵湵畴㠭ㄮⴰ敤歳潴⵰㍩㘸椮潳 

事实上,第一种方式(正如苹果文档中所提到的)正确地返回了大部分数据,还有一些额外的字节让我觉得这可能是BEncoding库中的一个错误。但是我对于ObjC的知识缺乏的可能性更大有过错..

 NSData *torrent = [BEncoding objectFromEncodedData:rawdata]; 

当我NSLog洪stream我得到以下内容:

 { ⋮ } 

那将是一个NSDictionary,那么,不是一个NSData。

 unsigned char aBuffer[[name length]]; [name getBytes:aBuffer length:[name length]]; NSLog(@"File name: %s", aBuffer); 

..回顾数据,但似乎有额外的unicode垃圾:

 File name: ubuntu-8.10-desktop-i386.iso) 

不,它检索文件名就好了; 你只是打印错误。 %s取一个Cstring,它以null结尾; 数据对象的字节不是空终止的(它们只是字节,不一定是任何编码中的字符,而0–它是一个空字符 – 是一个完全有效的字节)。 您将不得不分配一个字符,并将数组中的最后一个字符设置为0:

 size_t length = [name length] + 1; unsigned char aBuffer[length]; [name getBytes:aBuffer length:length]; aBuffer[length - 1] = 0; NSLog(@"File name: %s", aBuffer); 

但是在NSData对象中的空数据终止是错误的(除非你确实需要一个Cstring)。 我马上就会走对了。

我也试过[…] ..

 NSString *secondtry = [NSString stringWithCharacters:[name bytes] length:[name length] / sizeof(unichar)]; 

..但是这似乎是随机的中文字符:

 扵湵畴㠭ㄮⴰ敤歳潴⵰㍩㘸椮潳 

这是因为你的字节是UTF-8,它在(通常)一个字节中编码一个字符。

unichar是,而stringWithCharacters:length:接受,UTF-16。 在该编码中,一个字符(通常)是两个字节。 (因此,按sizeof(unichar)划分:将字节数除以2以得到字符数。)

所以你说“这是一些UTF-16的数据”,它从每两个字节去做字符; 每一对字节应该是两个字符,而不是一个,所以你有垃圾(原来主要是CJK的表意文字)。


你很好地回答了你自己的问题 ,除了stringWithUTF8String:stringWithCString:encoding:简单stringWithCString:encoding:用于UTF-8编码的string。

但是,当你有长度的时候(就像你有一个NSData的时候那样),使用initWithBytes:length:encoding:就更容易,也更合适。 这很容易,因为它不需要以null结尾的数据; 它只是使用你已经有的长度。 (不要忘记释放或autorelease它。)

这是我认为应该重新强调的重要一点。 事实certificate,

 NSString *content = [NSString stringWithUTF8String:[responseData bytes]]; 

是不一样的,

 NSString *content = [[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding]; 

第一个期望一个NULL终止字节的string,第二个没有。 在上述两种情况下,如果字节string未正确终止, content将在第一个示例中为NULL。

怎么样

 NSString *content = [[[NSString alloc] initWithData:myData encoding:NSUTF8StringEncoding] autorelease]; 

一个好的快速和肮脏的方法是使用NSStringstringWithFormat初始值stringWithFormat程序来帮助你。 string格式化不常用的function之一是能够在输出string时指定最大string长度。 使用这个方便的function,您可以很容易地将NSData转换为string:

 NSData *myData = [self getDataFromSomewhere]; NSString *string = [NSString stringWithFormat:@"%.*s", [myData length], [myData bytes]]; 

如果你想把它输出到日志,它可以更容易:

 NSLog(@"my Data: %.*s", [myData length], [myData bytes]); 

啊哈, NSString方法stringWithCString工作正常:

bencoding.h/.m文件添加到您的项目中,完整的.m文件:

 #import <Foundation/Foundation.h> #import "BEncoding.h" int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // Read raw file, and de-bencode NSData *rawdata = [NSData dataWithContentsOfFile:@"/path/to/a.torrent"]; NSData *torrent = [BEncoding objectFromEncodedData:rawdata]; // Get the file name NSData *infoData = [torrent valueForKey:@"info"]; NSData *nameData = [infoData valueForKey:@"name"]; NSString *filename = [NSString stringWithCString:[nameData bytes] encoding:NSUTF8StringEncoding]; NSLog(@"%@", filename); [pool drain]; return 0; } 

..和输出:

 ubuntu-8.10-desktop-i386.iso 

在我无法控制数据被转换成string(比如从networking中读取)的情况下,我宁愿使用NSString -initWithBytes:length:encoding:这样我就不依赖于以NULL结尾的string以获得定义的结果。 请注意,苹果的文档说,如果cString不是一个NULL结束的string,结果是不确定的。

你可以试试这个 这对我很好

 DLog(@"responeData: %@", [[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSASCIIStringEncoding] autorelease]); 

在NSData上使用一个类别:

的NSData + NSString.h

 @interface NSData (NSString) - (NSString *)toString; @end 

的NSData + NSString.m

 #import "NSData+NSString.h" @implementation NSData (NSString) - (NSString *)toString { Byte *dataPointer = (Byte *)[self bytes]; NSMutableString *result = [NSMutableString stringWithCapacity:0]; NSUInteger index; for (index = 0; index < [self length]; index++) { [result appendFormat:@"0x%02x,", dataPointer[index]]; } return result; } @end 

然后只是NSLog(@"Data is %@", [nsData toString])"

有时你需要从NSData创buildBase64编码的string。 例如,当你创build一个电子邮件MIME。 在这种情况下使用以下内容:

 #import "NSData+Base64.h" NSString *string = [data base64EncodedString]; 

我想你应该尝试这个代码,因为我已经使用它,它会工作。

 NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];