2015-08-08 130 views
9

我有一個NSData對象。我需要將其字節轉換爲字符串並以JSON形式發送。 description返回十六進制,並且不可靠(根據各種SO海報)。所以我在看這樣的代碼:將NSData字節數組轉換爲字符串?

NSUInteger len = [imageData length]; 
Byte *byteData = (Byte*)malloc(len); 
[imageData getBytes:&byteData length:len]; 

然後我如何發送byteData爲JSON?我想發送原始字節。

CODE:

NSString *jsonBase64 = [imageData base64EncodedString]; 
NSLog(@"BASE 64 FINGERPRINT: %@", jsonBase64); 
NSData *b64 = [NSData dataFromBase64String:jsonBase64]; 
NSLog(@"Equal: %d", [imageData isEqualToData:b64]); 
NSLog(@"b64: %@", b64); 
NSLog(@"original: %@", imageData); 
NSString *decoded = [[NSString alloc] initWithData:b64 encoding:NSUTF8StringEncoding]; 
NSLog(@"decoded: %@", decoded); 

我得到值,除了最後一行的一切 - decoded。 這將告訴我,原始字節未在NSUTF8encoding格式?

+1

是'imageData'的NSData對象,是數據可表示爲json字符串? – vadian

+1

你想要什麼格式的字節?十六進制碼? Base-64編碼的字符串?什麼? – rmaddy

+1

JSON的字符串,是的。根據標題。 – quantumpotato

回答

6

您是否嘗試過使用這樣的事情:

​​

這將打開你的NSData在一個base64字符串,並在另一邊,你只需要對它進行解碼。

編輯:@Lucas說你可以做這樣的事情:

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

,但我有一些問題,因爲一些特殊字符的這個方法,因爲我開始使用Base64字符串進行通信。

EDIT3:改掉這種方法base64EncodedString

@implementation NSData (Base64) 

    - (NSString *)base64EncodedString 
    { 
     return [self base64EncodedStringWithWrapWidth:0]; 
    } 

    //Helper Method 
    - (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth 
    { 
     //ensure wrapWidth is a multiple of 4 
     wrapWidth = (wrapWidth/4) * 4; 

     const char lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/"; 

     long long inputLength = [self length]; 
     const unsigned char *inputBytes = [self bytes]; 

     long long maxOutputLength = (inputLength/3 + 1) * 4; 
     maxOutputLength += wrapWidth? (maxOutputLength/wrapWidth) * 2: 0; 
     unsigned char *outputBytes = (unsigned char *)malloc((NSUInteger)maxOutputLength); 

     long long i; 
     long long outputLength = 0; 
     for (i = 0; i < inputLength - 2; i += 3) 
     { 
      outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2]; 
      outputBytes[outputLength++] = lookup[((inputBytes[i] & 0x03) << 4) | ((inputBytes[i + 1] & 0xF0) >> 4)]; 
      outputBytes[outputLength++] = lookup[((inputBytes[i + 1] & 0x0F) << 2) | ((inputBytes[i + 2] & 0xC0) >> 6)]; 
      outputBytes[outputLength++] = lookup[inputBytes[i + 2] & 0x3F]; 

      //add line break 
      if (wrapWidth && (outputLength + 2) % (wrapWidth + 2) == 0) 
      { 
       outputBytes[outputLength++] = '\r'; 
       outputBytes[outputLength++] = '\n'; 
      } 
     } 

     //handle left-over data 
     if (i == inputLength - 2) 
     { 
      // = terminator 
      outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2]; 
      outputBytes[outputLength++] = lookup[((inputBytes[i] & 0x03) << 4) | ((inputBytes[i + 1] & 0xF0) >> 4)]; 
      outputBytes[outputLength++] = lookup[(inputBytes[i + 1] & 0x0F) << 2]; 
      outputBytes[outputLength++] = '='; 
     } 
     else if (i == inputLength - 1) 
     { 
      // == terminator 
      outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2]; 
      outputBytes[outputLength++] = lookup[(inputBytes[i] & 0x03) << 4]; 
      outputBytes[outputLength++] = '='; 
      outputBytes[outputLength++] = '='; 
     } 

     if (outputLength >= 4) 
     { 
      //truncate data to match actual output length 
      outputBytes = realloc(outputBytes, (NSUInteger)outputLength); 
      return [[NSString alloc] initWithBytesNoCopy:outputBytes 
                length:(NSUInteger)outputLength 
               encoding:NSASCIIStringEncoding 
              freeWhenDone:YES]; 
     } 
     else if (outputBytes) 
     { 
      free(outputBytes); 
     } 
     return nil; 
    } 
+1

我不希望base64編碼,我需要原始字節作爲字符串 – quantumpotato

+1

,正如我之前告訴base64更安全一樣,因爲有時特殊字符會導致解碼從咬到字符串返回nill – rob180

+1

但我絕對需要原始位。那麼你會轉換回NSString? – quantumpotato

6
  1. 字符串在以前的協議棧的職位被認爲是「不可靠」的原因是因爲他們也被嘗試使用NSData的對象,其中的結束字節

    NSString *jsonString = [NSString stringWithUTF8String:[nsDataObj bytes]]; 
    // This is unreliable because it may result in NULL string values 
    
  2. :不正確地NULL終止

    而下面的例子應該給你你想要的結果,因爲NSData的字節串將正確終止:

    NSString *jsonString = [[NSString alloc] initWithBytes:[nsDataObj bytes] length:[nsDataObj length] encoding: NSUTF8StringEncoding]; 
    

你在正確的軌道上,並希望這能幫助您解決當前的問題。祝你好運!從NSData轉換爲NSString

NSData *imageData = [[NSData alloc] init]; 
imageData = UIImagePNGRepresentation(yourImage); 
+1

我會給這個鏡頭。 – quantumpotato

+1

你能夠得到這個工作? – ChrisHaze

+1

嗨@chrishaze,我從這個:( – quantumpotato

3

空終止並不是唯一的問題:

〜編輯〜

確保您從圖像像這樣宣告你的NSData對象。

NSString不適用於保存任意二進制數據。它期望編碼。

如果您的NSData包含無效的UTF-8序列,initializing the NSString will fail

的文檔是不是在這一點上完全清楚,但對於initWithData它說:

返回nil,如果由於某種原因(例如 如果數據並不代表編碼的有效數據)的初始化失敗。

另外:JSON規範將字符串定義爲sequence of Unicode characters

這意味着即使您能夠將您的原始數據轉換爲JSON字符串,如果代碼執行UTF-8驗證,解析可能會在接收端失敗。如果你不想使用Base64,take a look at the answers here

3

此答案中的所有代碼都是僞代碼片段,您需要自行將算法轉換爲Objective-C或其他語言。

你的問題提出了許多問題......你開始:

我有一個NSData對象。我需要將其字節轉換爲字符串並以JSON形式發送。描述返回十六進制,並且不可靠(根據各種SO海報)。

這似乎暗示要編碼字節作爲一個字符串,準備回另一端進行解碼,以字節爲單位。如果是這種情況下,你有多種選擇,如基地-64編碼等。如果你想要的東西簡單,你可以只是每個字節編碼爲兩個字符的十六進制值,僞代碼大綱:

NSMutableString *encodedString = @"".mutableCopy; 
foreach aByte in byteData 
    [encodedString appendFormat:@"%02x", aByte]; 

的格式%02x表示具有零填充的兩個十六進制數字。這會產生一個字符串,它可以以JSON的形式發送,並且很容易在另一端進行解碼。導線上的字節大小爲,可能爲字節長度的兩倍,因爲UTF-8是JSON在導線上的推薦編碼。

但是響應的回答一個你寫的:

但我需要絕對的原始位。

這是什麼意思?您的接收器是否會將它獲取的JSON字符串解釋爲一系列原始字節?如果是這樣,你有一些問題需要解決。 JSON字符串是JavaScript字符串的子集,存儲爲UCS-2或UTF-16,即它們是16位值序列,不是8位值。如果您將每個字節編碼爲字符串中的字符,則它將使用16位表示,如果您的接收器可以訪問字節流,則必須跳過其他字節。當然,如果接收者每次訪問一個字符時,每個16位字符可以被截斷回8位字節。現在你可能會認爲如果你採取這種方法,那麼每個8位字節可以作爲字符串的一部分輸出,但這不起作用。雖然所有值1-255都是有效的Unicode字符代碼點,而JavaScript/JSON允許字符串中的NUL(0值),但並非所有這些值都是可打印的,您不能將雙引號"放入字符串中而不會將其轉義,並且轉義字符是\ - 所有這些都需要編碼到字符串中。你最終的東西,如:

NSMutableString *encodedString = @"".mutableCopy; 
foreach aByte in byteData 
    if (isprint(aByte) && aByte != '"' && aByte != '\\') 
     [encodedString appendFormat:@"%c", aByte]; 
    otherwise 
     [encodedString appendFormat:@"\\u00%02x", aByte]; // JSON unicode escape sequence 

這將產生一個字符串,當由JSON解析解碼器會給你的每一個字節一個字符(16位),前8位是零。 但是如果這個字符串傳遞給JSON編碼器將編碼的Unicode轉義序列,其已經被編碼......所以,你真的需要通過電線自己避免這種發送此字符串...

困惑?變得複雜?那麼你爲什麼要嘗試將二進制字節數據作爲字符串發送?你永遠不會說你的高級目標是什麼,或者什麼都知道字節數據(例如,它代表某種編碼中的字符)

如果這實際上只是一個字節數組,那麼爲什麼不發送它作爲JSON數組數組 - 一個字節只是0-255範圍內的一個數字。要做到這一點,你會沿着線的使用代碼:

NSMutableArray *encodedBytes = [NSMutableArray new]; 
foreach aByte in byteData 
    [encodedBytes addObject:@(aByte)]; // add aByte as an NSNumber object 

現在通過encodedBytesNSJSONSerialisation,它會發送號碼的JSON陣列上線,接收器將扭轉過程中包裝每個字節回一個字節緩衝區,你有你回來的字節。

該方法避免了有效字符串,編碼和轉義的所有問題。

HTH

+0

我試圖發送二進制數據,因爲這是API的要求。它作爲請求主體發送。 – quantumpotato

+0

哪個API需要二進制數據?如果它是接收器上的一個,並且您試圖通過將數據作爲JSON傳遞來調用它,那麼只需將它作爲通信的一部分通過線路傳輸時,就需要以某種形式*對二進制數據*進行編碼。您*不需要*將其編碼爲字符串,但您可以。第一個解決方案(編碼爲十六進制或base-64字符串)或最後一個解決方案(編碼爲數字數組)將滿足您的需求。如果數據很大,你可能想選擇base-64作爲最簡單的最緊湊的方法,但否則會做任何事情。 HTH – CRD

+0

我注意到你說「發送請求正文」,這表明你正在嘗試與web服務進行通信,並且有一些它所期望的規範,而不是用你自己的基於服務器的代碼調用某些API。如果是這種情況,您需要在關於API的問題以及它期望的問題中提供更多詳細信息 - API中不應要求JSON中的二進制數據,也不要指定如何對它進行編碼--JSON沒有將二進制數據作爲基本數據類型。 – CRD

相關問題