【问题标题】:Compress/Decompress NSString in objective-c (iphone) using GZIP or deflate使用 GZIP 或 deflate 在 Objective-c (iphone) 中压缩/解压缩 NSString
【发布时间】:2011-03-02 05:58:38
【问题描述】:

我在 Windows Azure 上运行了一个 Web 服务,它返回我在 iPhone 应用程序中使用的 JSON。

不幸的是,Windows Azure 似乎还不支持动态响应的压缩(说来话长),所以我决定通过返回一个未压缩的 JSON 包来解决这个问题,该包包含一个压缩(使用 GZIP)字符串。

例如

{"Error":null,"IsCompressed":true,"Success":true,"Value":"vWsAAB+LCAAAAAAAB..etc.."}

... 其中 value 是以 JSON 表示的复杂对象的压缩字符串。

这真的很容易在服务器上实现,但是对于我来说,我无法弄清楚如何将 gzip 压缩的 NSString 解压缩为未压缩的 NSString,我可以找到的 zlib 等的所有示例都在处理文件等.

谁能给我任何关于如何做到这一点的线索? (我也很高兴使用 deflate 的解决方案,因为我可以将服务器端实现更改为也使用 deflate)。

谢谢!!

史蒂文

编辑 1: 啊,我看到 ASIHTTPRequest 在其源代码中使用了以下函数:

//uncompress gzipped data with zlib
+ (NSData *)uncompressZippedData:(NSData*)compressedData;

...而且我知道我可以将 NSString 转换为 NSData,所以我会看看这是否能引导我到任何地方!

编辑 2:不幸的是,编辑 1 中描述的方法并没有引导我到任何地方。

编辑 3: 根据以下关于 base64 编码/解码的建议,我想出了以下代码。您可以猜到,encodedGzippedString 是一个字符串“你好,我的名字是 Steven Elliott”,它被 gzip 压缩,然后转换为 base64 字符串。不幸的是,使用 NSLog 打印的结果只是空白。

NSString *encodedGzippedString = @"GgAAAB+LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee++997o7nU4n99//P1xmZAFs9s5K2smeIYCqyB8/fnwfPyK+uE6X2SJPiyZ93eaX+TI9Lcuiatvx/wOwYc0HGgAAAA==";
NSData *decodedGzippedData = [NSData dataFromBase64String:encodedGzippedString];
NSData* unGzippedJsonData = [ASIHTTPRequest uncompressZippedData:decodedGzippedData];   
NSString* unGzippedJsonString = [[NSString alloc] initWithData:unGzippedJsonData encoding:NSASCIIStringEncoding];       
NSLog(@"Result: %@", unGzippedJsonString);  

【问题讨论】:

    标签: iphone objective-c gzip deflate http-compression


    【解决方案1】:

    搞了这么久,终于找到了解决这个问题的办法!

    上面的答案都没有帮助我,就像他们看起来一样有希望。最后,我能够使用 gzip 使用 .net 的 chilkat 框架在服务器上压缩字符串......然后使用 iOS 的 chilkat 框架在 iphone 上解压缩它(尚未发布,但如果您通过电子邮件发送人直接)。

    chilkat 框架让这一切变得超级简单,让开发者赞不绝口!

    【讨论】:

    • 嗨,你能提供任何确切的框架链接吗?
    【解决方案2】:

    您的“压缩”字符串不是原始 GZIP 数据,它采用某种编码,允许将这些字节存储在字符串中——看起来像 base-64 或类似的东西。要从中获取 NSData,您需要将其解码为 NSData。

    如果它真的是 base-64,请查看这篇博文并附上代码: http://cocoawithlove.com/2009/06/base64-encoding-options-on-mac-and.html 这会做你想做的。

    一旦你有了一个 NSData 对象,ASIHTTPRequest 方法可能会按照你的意愿去做。

    【讨论】:

    • 您好 Quixoto,感谢您的回复。如果您在我的原始帖子中检查编辑 3,您会看到在我尝试更多使用您的建议后发生了什么。再次感谢
    • 这是一组合理的步骤,所以不清楚的是:传输的字符串肯定是Base64吗? (可能)Windows 中原始字符串的原始编码是什么?您在解码时选择了 ASCII 编码,这不太可能是正确的。 NSData 缓冲区中的数据是否有说服力?
    【解决方案3】:

    这对我有用: 从字符串 gzipeed,然后 base64 编码 解压缩字符串(全部为 utf8)。

    #import "base64.h"
    #import "NSData+Compression.h"
    
    ...
    
    +(NSString *)gunzipBase64StrToStr:(NSString *)stringValue {
        //now we decode from Base64
        Byte inputData[[stringValue lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];//prepare a Byte[]
        [[stringValue dataUsingEncoding:NSUTF8StringEncoding] getBytes:inputData];//get the pointer of the data
        size_t inputDataSize = (size_t)[stringValue length];
        size_t outputDataSize = EstimateBas64DecodedDataSize(inputDataSize);//calculate the decoded data size
        Byte outputData[outputDataSize];//prepare a Byte[] for the decoded data
        Base64DecodeData(inputData, inputDataSize, outputData, &outputDataSize);//decode the data
        NSData *theData = [[NSData alloc] initWithBytes:outputData length:outputDataSize];//create a NSData object from the decoded data
                                                                                          //NSLog(@"DATA: %@ \n",[theData description]);
    
        //And now we gunzip:
        theData=[theData gzipInflate];//make bigger==gunzip
        return [[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding];
    }
    
    @end
    

    【讨论】:

      【解决方案4】:

      我需要在 iPhone 上使用 Objective-c 压缩数据并在 PHP 上解压缩。这是我在 XCode 11.5 和 iOS 12.4 中使用的:

      iOS Objective-c 压缩解压测试 在 Build Phases -> Link Binary With Library 中包含 libcompression.tbd。然后包含标题。

      #include "compression.h"
      
      
      NSLog(@"START META DATA COMPRESSION");
      NSString *testString = @"THIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TEST";
      NSData *theData = [testString dataUsingEncoding:NSUTF8StringEncoding];
      size_t src_size = theData.length;
      uint8_t *src_buffer = (uint8_t*)[theData bytes];
      size_t dst_size = src_size+4096;
      uint8_t *dst_buffer = (uint8_t*)malloc(dst_size);
      dst_size = compression_encode_buffer(dst_buffer, dst_size, src_buffer, src_size, NULL, COMPRESSION_ZLIB);
      NSLog(@"originalsize:%zu compressed:%zu", src_size, dst_size);
      NSData *dataData = [NSData dataWithBytes:dst_buffer length:sizeof(dst_buffer)];
      NSString *compressedDataBase64String = [dataData base64EncodedStringWithOptions:0];    
      
      NSLog(@"Compressed Data %@", compressedDataBase64String);
      
      NSLog(@"START META DATA DECOMPRESSION");
      src_size = compression_decode_buffer(src_buffer, src_size, dst_buffer, dst_size, NULL, COMPRESSION_ZLIB);
      NSData *decompressed = [[NSData alloc] initWithBytes:src_buffer length:src_size];
      NSString *decTestString;
      decTestString = [[NSString alloc] initWithData:decompressed encoding:NSASCIIStringEncoding];
      
      NSLog(@"DECOMPRESSED DATA %@", decTestString);
      
      free(dst_buffer);
      

      在 PHP 端,我使用以下函数解压数据:

      function decompressString($compressed_string) {
      
          //NEED RAW GZINFLATE FOR COMPATIBILITY WITH IOS COMPRESSION_ZLIB WITH IETF RFC 1951
          $full_string = gzinflate($compressed_string);
          return $full_string;
      
      }  
      

      【讨论】: