将 NSData 字节转换为 NSString?

发布于 2024-07-13 12:06:40 字数 1625 浏览 9 评论 0原文

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

How do I conversion the name into a 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 缺乏了解更有可能是错误..

I'm trying to use the BEncoding ObjC class to decode a .torrent file.

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

When I NSLog torrent I get the following:

{
    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;
....

How do I convert the name into a NSString? I have tried..

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);

..which retrives the data, but seems to have additional unicode rubbish after it:

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

I have also tried (from here)..

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

..but this seems to return a bunch of random characters:

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

The fact the first way (as mentioned in the Apple documentation) returns most of the data correctly, with some additional bytes makes me think it might be an error in the BEncoding library.. but my lack of knowledge about ObjC is more likely to be at fault..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

泅渡 2024-07-20 12:06:41

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

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

不同

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

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

That's an important point that should be re-emphasized I think. It turns out that,

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

is not the same as,

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

the first expects a NULL terminated byte string, the second doesn't. In the above two cases content will be NULL in the first example if the byte string isn't correctly terminated.

毅然前行 2024-07-20 12:06:41

怎么样

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

How about

NSString *content = [[[NSString alloc] initWithData:myData
                                           encoding:NSUTF8StringEncoding] autorelease];
您的好友蓝忘机已上羡 2024-07-20 12:06:41
NSData *torrent = [BEncoding objectFromEncodedData:rawdata]; 
  

当我使用 NSLog torrent 时,我得到以下信息:

<前><代码>{

}

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

unsigned char aBuffer[[名称长度]]; 
  [名称 getBytes:aBuffer 长度:[名称长度]]; 
  NSLog(@"文件名:%s", aBuffer); 
  

..它检索数据,但后面似乎有额外的 unicode 垃圾:

文件名:ubuntu-8.10-desktop-i386.iso) 
  

不,它检索文件名很好; 您只是打印错误。 %s 接受一个以 null 结尾的 C 字符串; 数据对象的字节不是以 null 结尾的(它们只是字节,不一定是任何编码中的字符,并且 0(作为字符为 null)是完全有效的字节)。 您必须再分配一个字符,并将数组中的最后一个字符设置为 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);

但是以 null 终止 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 : 比 UTF-8 编码字符串的 stringWithCString:encoding: 更简单。

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

NSData *torrent = [BEncoding objectFromEncodedData:rawdata];

When I NSLog torrent I get the following:

{
    ⋮
}

That would be an NSDictionary, then, not an NSData.

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

..which retrives the data, but seems to have additional unicode rubbish after it:

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

No, it retrieved the filename just fine; you simply printed it incorrectly. %s takes a C string, which is null-terminated; the bytes of a data object are not null-terminated (they are just bytes, not necessarily characters in any encoding, and 0—which is null as a character—is a perfectly valid byte). You would have to allocate one more character, and set the last one in the array to 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);

But null-terminating the data in an NSData object is wrong (except when you really do need a C string). I'll get to the right way in a moment.

I have also tried […]..

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

..but this seems to return random Chinese characters:

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

That's because your bytes are UTF-8, which encodes one character in (usually) one byte.

unichar is, and stringWithCharacters:length: accepts, UTF-16. In that encoding, one character is (usually) two bytes. (Hence the division by sizeof(unichar): it divides the number of bytes by 2 to get the number of characters.)

So you said “here's some UTF-16 data”, and it went and made characters from every two bytes; each pair of bytes was supposed to be two characters, not one, so you got garbage (which turned out to be mostly CJK ideographs).


You answered your own question pretty well, except that stringWithUTF8String: is simpler than stringWithCString:encoding: for UTF-8-encoded strings.

However, when you have the length (as you do when you have an NSData), it is even easier—and more proper—to use initWithBytes:length:encoding:. It's easier because it does not require null-terminated data; it simply uses the length you already have. (Don't forget to release or autorelease it.)

手心的海 2024-07-20 12:06:41

一个快速而肮脏的方法是使用 NSString 的 stringWithFormat 初始化器来帮助您。 字符串格式化不太常用的功能之一是能够在输出字符串时指定最大字符串长度。 使用这个方便的功能可以让您非常轻松地将 NSData 转换为字符串:

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

如果您想将其输出到日志,则可以更容易:

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

A nice quick and dirty approach is to use NSString's stringWithFormat initializer to help you out. One of the less-often used features of string formatting is the ability to specify a mximum string length when outputting a string. Using this handy feature allows you to convert NSData into a string pretty easily:

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

If you want to output it to the log, it can be even easier:

NSLog(@"my Data: %.*s", [myData length], [myData bytes]);
奶气 2024-07-20 12:06:41

啊哈,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

Aha, the NSString method stringWithCString works correctly:

With the bencoding.h/.m files added to your project, the complete .m file:

#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;
}

..and the output:

ubuntu-8.10-desktop-i386.iso
谈下烟灰 2024-07-20 12:06:41

如果我无法控制数据转换为字符串,例如从网络读取,我更喜欢使用 NSString -initWithBytes:length:encoding: ,这样我就不会依赖于 NULL 终止的字符串以获得定义的结果。 请注意,Apple 的文档指出,如果 cString 不是以 NULL 结尾的字符串,则结果是未定义的。

In cases where I don't have control over the data being transformed into a string, such as reading from the network, I prefer to use NSString -initWithBytes:length:encoding: so that I'm not dependent upon having a NULL terminated string in order to get defined results. Note that Apple's documentation says if cString is not a NULL terminated string, that the results are undefined.

想挽留 2024-07-20 12:06:41

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

Use a category on 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

Then just NSLog(@"Data is %@", [nsData toString])"

夜吻♂芭芘 2024-07-20 12:06:41

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

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

You can try this. Fine with me.

DLog(@"responeData: %@", [[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSASCIIStringEncoding] autorelease]);
没有你我更好 2024-07-20 12:06:41

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

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

Sometimes you need to create Base64 encoded string from NSData. For instance, when you create a e-mail MIME. In this case use the following:

#import "NSData+Base64.h"
NSString *string = [data base64EncodedString];
温暖的光 2024-07-20 12:06:41

这会起作用。

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

This will work.

NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文