BEncoding ObjC class を使用して.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);
..これはデータを取得しますが、その後に追加のユニコードのゴミがあるようです:
File name: ubuntu-8.10-desktop-i386.iso)
私も試しました( ここから )..
NSString *secondtry = [NSString stringWithCharacters:[name bytes] length:[name length] / sizeof(unichar)];
..しかし、これはランダムな文字の束を返すようです:
扵湵畴㠭ㄮⴰ敤歳潴⵰㍩㘸椮潳
最初の方法(Appleドキュメンテーション)に記載されているように)は、いくつかの追加のバイトを使用して、ほとんどのデータを正しく返します。 ObjCについての知識の過失が原因である可能性が高い。
_NSData *torrent = [BEncoding objectFromEncodedData:rawdata];
_NSLogトレントを取得すると、次の結果が得られます。
_{ ⋮ }
_
NSDataではなく、NSDictionaryになります。
_unsigned char aBuffer[[name length]]; [name getBytes:aBuffer length:[name length]]; NSLog(@"File name: %s", aBuffer);
_..これはデータを取得しますが、その後に追加のユニコードのゴミがあるようです:
_File name: ubuntu-8.10-desktop-i386.iso)
_
いいえ、ファイル名は問題なく取得されました。間違って印刷しただけです。 _%s
_はヌル文字で終了するC文字列を受け取ります。データオブジェクトのバイトはnullで終了しません(これらは単なるバイトであり、必ずしもエンコーディングの文字ではなく、0(文字としてnull)は完全に有効なバイトです)。もう1文字を割り当て、配列の最後の文字を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オブジェクト内のデータのヌル終了は間違っています(本当にdoC文字列が必要な場合を除く)。すぐに正しい方法に行きます。
私も試しました[…] ..
_NSString *secondtry = [NSString stringWithCharacters:[name bytes] length:[name length] / sizeof(unichar)];
_..しかし、これはランダムな漢字を返すようです:
_扵湵畴㠭ㄮⴰ敤歳潴⵰㍩㘸椮潳
_
これは、バイトが(通常)1バイトで1文字をエンコードするUTF-8であるためです。
unichar
はUTF-16であり、_stringWithCharacters:length:
_は受け入れます。そのエンコーディングでは、1文字は(通常)2バイトです。 (したがって、sizeof(unichar)
による除算:バイト数を2で除算して文字数を取得します。)
「ここにUTF-16データがあります」と言って、2バイトごとに文字を作成しました。バイトの各ペアは1文字ではなく2文字であると想定されていたため、ガベージを受け取りました(ほとんどがCJK表意文字であることが判明しました)。
あなたは自分の質問に答えました UTF-8でエンコードされた文字列の_stringWithUTF8String:
_は_stringWithCString:encoding:
_よりも単純であることを除いて、かなりよくできています。
ただし、長さがある場合(NSDataがある場合と同じように)、_initWithBytes:length:encoding:
_を使用する方が簡単で、より適切です。ヌル終了データを必要としないため、簡単です。既に持っている長さを使用するだけです。 (リリースまたは自動リリースすることを忘れないでください。)
それは、私が思うに再強調されるべき重要なポイントです。それは判明しました、
NSString *content = [NSString stringWithUTF8String:[responseData bytes]];
とは異なり、
NSString *content = [[NSString alloc] initWithBytes:[responseData bytes]
length:[responseData length] encoding: NSUTF8StringEncoding];
最初はNULLで終了するバイト文字列を期待しますが、2番目はそうではありません。上記の2つの場合、バイト文字列が正しく終了していない場合、最初の例でcontent
はNULLになります。
どう?
NSString *content = [[[NSString alloc] initWithData:myData
encoding:NSUTF8StringEncoding] autorelease];
素晴らしく素早いアプローチは、NSString
のstringWithFormat
初期化子を使用して手助けすることです。あまり使用されない文字列フォーマットの機能の1つは、文字列を出力するときに最大文字列長を指定する機能です。この便利な機能を使用すると、NSData
を非常に簡単に文字列に変換できます。
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
ネットワークからの読み取りなど、文字列に変換されるデータを制御できない場合は、NSString -initWithBytes:length:encoding:
これにより、定義済みの結果を取得するためにNULLで終了する文字列を持つことに依存しなくなりました。 Appleのドキュメントには、cStringがNULLで終了する文字列でない場合、結果は未定義であると書かれていることに注意してください。
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])"
これを試すことができます。元気です。
DLog(@"responeData: %@", [[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSASCIIStringEncoding] autorelease]);
これは動作します。
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDataからBase64エンコード文字列を作成する必要がある場合があります。たとえば、電子メールMIMEを作成するとき。この場合、次を使用します。
#import "NSData+Base64.h"
NSString *string = [data base64EncodedString];