iOS 数据请求 GZip数据压缩和解压缩问题

一、客户端-服务端数据压缩解压流程

客户端生成request,设置header允许使用压缩("Accept-Encoding","gzip"),即是告诉服务器,客户端支持压缩,但凡可以压缩的服务器,尽管来吧!服务器收到这个header,如果它支持压缩,可以通过压缩方式输出数据,然后再写入response的header("Content-Encoding","gzip")

1.以ASIHttpRequest为例,代码如下:

    NSURL* requestURL = [NSURL URLWithString:_listURL];
    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:requestURL];
    // 默认为YES, 你可以设定它为NO来禁用gzip压缩
    [request setAllowCompressedResponse:YES];
    [request setDelegate:self];
    [request startAsynchronous];
    如果是普通的URLRequest,只要: request.setHeader("Accept-Encoding","gzip");
2.服务器端返回: response.setHeader("Content-Encoding","gzip");

 libz库
  libz库是官方的一个库,貌似ASIHttpRequest也是用这个库解压的,当我们获得压缩过的data数据以后(方法与上面类似,只是获得    了  

 普通的data数据响应),可以使用这种方法解压数据,解压方法如下所示

 数据压缩参考:http://www.clintharris.net/2009/how-to-gzip-data-in-memory-using-objective-c/

 数据解压缩参考:ASIHttpRequest库的文件:ASIDataDecompressor.m

// 头文件:GzipUtility.h

#import 

@interface GzipUtility : NSObject

        // 数据压缩

        + (NSData *)compressData:(NSData*)uncompressedData;  

        // 数据解压缩

        + (NSData *)decompressData:(NSData *)compressedData;

@end


// 实现文件:GzipUtility.m

#import "GzipUtility.h"

#import "zlib.h"

@implementation GzipUtility

+(NSData*) compressData: (NSData*)uncompressedData  {  

    /* 

     Special thanks to Robbie Hanson of Deusty Designs for sharing sample code 

     showing how deflateInit2() can be used to make zlib generate a compressed 

     file with gzip headers: 

     http://deusty.blogspot.com/2007/07/gzip-compressiondecompression.html 

     */  

    

    if (!uncompressedData || [uncompressedData length] == 0)  {  

        NSLog(@"%s: Error: Can't compress an empty or null NSData object.", __func__);  

        return nil;  

    }  

    

    /* Before we can begin compressing (aka "deflating") data using the zlib 

     functions, we must initialize zlib. Normally this is done by calling the 

     deflateInit() function; in this case, however, we'll use deflateInit2() so 

     that the compressed data will have gzip headers. This will make it easy to 

     decompress the data later using a tool like gunzip, WinZip, etc. 

     

     deflateInit2() accepts many parameters, the first of which is a C struct of 

     type "z_stream" defined in zlib.h. The properties of this struct are used to 

     control how the compression algorithms work. z_stream is also used to 

     maintain pointers to the "input" and "output" byte buffers (next_in/out) as 

     well as information about how many bytes have been processed, how many are 

     left to process, etc. */  

    z_stream zlibStreamStruct;  

    zlibStreamStruct.zalloc    = Z_NULL; // Set zalloc, zfree, and opaque to Z_NULL so  

    zlibStreamStruct.zfree     = Z_NULL; // that when we call deflateInit2 they will be  

    zlibStreamStruct.opaque    = Z_NULL; // updated to use default allocation functions.  

    zlibStreamStruct.total_out = 0; // Total number of output bytes produced so far  

    zlibStreamStruct.next_in   = (Bytef*)[uncompressedData bytes]; // Pointer to input bytes  

    zlibStreamStruct.avail_in  = [uncompressedData length]; // Number of input bytes left to process  

    

    /* Initialize the zlib deflation (i.e. compression) internals with deflateInit2(). 

     The parameters are as follows: 

     

     z_streamp strm - Pointer to a zstream struct 

     int level      - Compression level. Must be Z_DEFAULT_COMPRESSION, or between 

     0 and 9: 1 gives best speed, 9 gives best compression, 0 gives 

     no compression. 

     int method     - Compression method. Only method supported is "Z_DEFLATED". 

     int windowBits - Base two logarithm of the maximum window size (the size of 

     the history buffer). It should be in the range 8..15. Add 

     16 to windowBits to write a simple gzip header and trailer 

     around the compressed data instead of a zlib wrapper. The 

     gzip header will have no file name, no extra data, no comment, 

     no modification time (set to zero), no header crc, and the 

     operating system will be set to 255 (unknown). 

     int memLevel   - Amount of memory allocated for internal compression state. 

     1 uses minimum memory but is slow and reduces compression 

     ratio; 9 uses maximum memory for optimal speed. Default value 

     is 8. 

     int strategy   - Used to tune the compression algorithm. Use the value 

     Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data 

     produced by a filter (or predictor), or Z_HUFFMAN_ONLY to 

     force Huffman encoding only (no string match) */  

    int initError = deflateInit2(&zlibStreamStruct, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY);  

    if (initError != Z_OK)  

    {  

        NSString *errorMsg = nil;  

        switch (initError)  

        {  

            case Z_STREAM_ERROR:  

                errorMsg = @"Invalid parameter passed in to function.";  

                break;  

            case Z_MEM_ERROR:  

                errorMsg = @"Insufficient memory.";  

                break;  

            case Z_VERSION_ERROR:  

                errorMsg = @"The version of zlib.h and the version of the library linked do not match.";  

                break;  

            default:  

                errorMsg = @"Unknown error code.";  

                break;  

        }  

        NSLog(@"%s: deflateInit2() Error: \"%@\" Message: \"%s\"", __func__, errorMsg, zlibStreamStruct.msg);  

        [errorMsg release];  

        return nil;  

    }  

    

    // Create output memory buffer for compressed data. The zlib documentation states that  

    // destination buffer size must be at least 0.1% larger than avail_in plus 12 bytes.  

    NSMutableData *compressedData = [NSMutableData dataWithLength:[uncompressedData length] * 1.01 + 12];  

    

    int deflateStatus;  

    do  

    {  

        // Store location where next byte should be put in next_out  

        zlibStreamStruct.next_out = [compressedData mutableBytes] + zlibStreamStruct.total_out;  

        

        // Calculate the amount of remaining free space in the output buffer  

        // by subtracting the number of bytes that have been written so far  

        // from the buffer's total capacity  

        zlibStreamStruct.avail_out = [compressedData length] - zlibStreamStruct.total_out;  

        

        /* deflate() compresses as much data as possible, and stops/returns when 

         the input buffer becomes empty or the output buffer becomes full. If 

         deflate() returns Z_OK, it means that there are more bytes left to 

         compress in the input buffer but the output buffer is full; the output 

         buffer should be expanded and deflate should be called again (i.e., the 

         loop should continue to rune). If deflate() returns Z_STREAM_END, the 

         end of the input stream was reached (i.e.g, all of the data has been 

         compressed) and the loop should stop. */  

        deflateStatus = deflate(&zlibStreamStruct, Z_FINISH);  

        

    } while ( deflateStatus == Z_OK );        

    

    // Check for zlib error and convert code to usable error message if appropriate  

    if (deflateStatus != Z_STREAM_END)  

    {  

        NSString *errorMsg = nil;  

        switch (deflateStatus)  

        {  

            case Z_ERRNO:  

                errorMsg = @"Error occured while reading file.";  

                break;  

            case Z_STREAM_ERROR:  

                errorMsg = @"The stream state was inconsistent (e.g., next_in or next_out was NULL).";  

                break;  

            case Z_DATA_ERROR:  

                errorMsg = @"The deflate data was invalid or incomplete.";  

                break;  

            case Z_MEM_ERROR:  

                errorMsg = @"Memory could not be allocated for processing.";  

                break;  

            case Z_BUF_ERROR:  

                errorMsg = @"Ran out of output buffer for writing compressed bytes.";  

                break;  

            case Z_VERSION_ERROR:  

                errorMsg = @"The version of zlib.h and the version of the library linked do not match.";  

                break;  

            default:  

                errorMsg = @"Unknown error code.";  

                break;  

        }  

        NSLog(@"%s: zlib error while attempting compression: \"%@\" Message: \"%s\"", __func__, errorMsg, zlibStreamStruct.msg);  

        [errorMsg release];  

        

        // Free data structures that were dynamically created for the stream.  

        deflateEnd(&zlibStreamStruct);  

        

        return nil;  

    }  

    

    // Free data structures that were dynamically created for the stream.  

    deflateEnd(&zlibStreamStruct);  

    

    [compressedData setLength: zlibStreamStruct.total_out];  

    

    return compressedData;  

}  


+ (NSData *)decompressData:(NSData *)compressedData {

    z_stream zStream;

    zStream.zalloc = Z_NULL;

    zStream.zfree = Z_NULL;

    zStream.opaque = Z_NULL;

    zStream.avail_in = 0;

    zStream.next_in = 0;

    int status = inflateInit2(&zStream, (15+32));

    

    if (status != Z_OK) {

        return nil;

    }

    

    Bytef *bytes = (Bytef *)[compressedData bytes];

    NSUInteger length = [compressedData length];

    

    NSUInteger halfLength = length/2;

    NSMutableData *uncompressedData = [NSMutableData dataWithLength:length+halfLength];

    

    zStream.next_in = bytes;

    zStream.avail_in = (unsigned int)length;

    zStream.avail_out = 0;

    

    NSInteger bytesProcessedAlready = zStream.total_out;

    while (zStream.avail_in != 0) {

        

        if (zStream.total_out - bytesProcessedAlready >= [uncompressedData length]) {

            [uncompressedData increaseLengthBy:halfLength];

        }

        

        zStream.next_out = (Bytef*)[uncompressedData mutableBytes] + zStream.total_out-bytesProcessedAlready;

        zStream.avail_out = (unsigned int)([uncompressedData length] - (zStream.total_out-bytesProcessedAlready));

        

        status = inflate(&zStream, Z_NO_FLUSH);

        

        if (status == Z_STREAM_END) {

            break;

        } else if (status != Z_OK) {

            return nil;

        }

    }

    

    status = inflateEnd(&zStream);

    if (status != Z_OK) {

        return nil;

    }

    

    [uncompressedData setLength: zStream.total_out-bytesProcessedAlready];  // Set real length


    return uncompressedData;    

}


@end


你可能感兴趣的:(iOS 数据请求 GZip数据压缩和解压缩问题)