50

我正在尝试使用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)];

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

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

第一种方法(如 Apple 文档中所述)正确返回大部分数据的事实,以及一些额外的字节让我认为这可能是 BEncoding 库中的一个错误。但我对 ObjC 的了解更可能是有过错..

4

10 回答 10

100

这是我认为应该再次强调的重要一点。事实证明,

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

不一样,

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

第一个需要一个 NULL 终止的字节字符串,第二个不需要。在上述两种情况下content,如果字节字符串未正确终止,则在第一个示例中将为 NULL。

于 2009-03-02T23:39:24.243 回答
20

怎么样

NSString *content = [[[NSString alloc] initWithData:myData
                                           encoding:NSUTF8StringEncoding] autorelease];
于 2011-02-10T01:24:16.877 回答
19
NSData *torrent = [BEncoding objectFromEncodedData:rawdata];

当我 NSLog torrent 我得到以下信息:

{
    ⋮
}

那将是一个 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接受一个以 null 结尾的 C 字符串;数据对象的字节不是以空值结尾的(它们只是字节,不一定是任何编码中的字符,而 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 对象中以空值结尾的数据是错误的(除非您确实需要 C 字符串)。一会儿我会找到正确的方法。

我也试过 […]..

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:UTF-8 编码的字符串更简单。

然而,当你有长度时(就像你有一个 NSData 时一样),使用initWithBytes:length:encoding:. 它更容易,因为它不需要以空值结尾的数据;它只是使用您已有的长度。(不要忘记释放或自动释放它。)

于 2009-02-17T00:07:11.983 回答
7

一个不错的快速而肮脏的方法是使用NSString'sstringWithFormat初始化程序来帮助您。字符串格式化的不太常用的功能之一是能够在输出字符串时指定最大字符串长度。使用这个方便的功能可以NSData很容易地转换成字符串:

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

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

NSLog(@"my Data: %.*s", [myData length], [myData bytes]);
于 2009-08-26T00:49:14.503 回答
6

啊哈,该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
于 2009-02-15T06:22:13.153 回答
2

在我无法控制要转换为字符串的数据的情况下,例如从网络读取数据,我更喜欢使用NSString -initWithBytes:length:encoding:它,这样我就不必依赖以 NULL 结尾的字符串来获得定义的结果。请注意,Apple 的文档说如果 cString 不是以 NULL 结尾的字符串,则结果未定义。

于 2009-02-16T01:18:58.200 回答
2

在 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])"

于 2012-03-02T00:06:33.390 回答
2

你可以试试这个。我都可以。

DLog(@"responeData: %@", [[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSASCIIStringEncoding] autorelease]);
于 2013-08-05T09:45:51.970 回答
0

有时您需要从 NSData 创建 Base64 编码的字符串。例如,当您创建电子邮件 MIME 时。在这种情况下,请使用以下内容:

#import "NSData+Base64.h"
NSString *string = [data base64EncodedString];
于 2012-10-05T15:21:14.230 回答
0

这将起作用。

NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
于 2013-06-05T06:16:21.180 回答