Is there a practical way to compress NSData?

后端 未结 7 1903
感情败类
感情败类 2020-12-14 11:40

I haven\'t seen any documentation on the topic, but that doesn\'t mean it doesn\'t exist.

相关标签:
7条回答
  • 2020-12-14 11:54

    Following @Zaph & @Brad Larson's posts, below are the 2 methods gzipInflate and gzipDeflate that work just fine to compress/decompress NSData. (code reformatted from cocoadev.com/wiki/NSDataCategory

    #import "zlib.h"
    // don't forget to add libz.1.2.x.dylib into your project
    
    - (NSData *)gzipInflate:(NSData*)data
    {
        if ([data length] == 0) return data;
    
        unsigned full_length = [data length];
        unsigned half_length = [data length] / 2;
    
        NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
        BOOL done = NO;
        int status;
    
        z_stream strm;
        strm.next_in = (Bytef *)[data bytes];
        strm.avail_in = [data length];
        strm.total_out = 0;
        strm.zalloc = Z_NULL;
        strm.zfree = Z_NULL;
    
        if (inflateInit2(&strm, (15+32)) != Z_OK) return nil;
        while (!done)
        {
            // Make sure we have enough room and reset the lengths.
            if (strm.total_out >= [decompressed length])
                [decompressed increaseLengthBy: half_length];
            strm.next_out = [decompressed mutableBytes] + strm.total_out;
            strm.avail_out = [decompressed length] - strm.total_out;
    
            // Inflate another chunk.
            status = inflate (&strm, Z_SYNC_FLUSH);
            if (status == Z_STREAM_END) done = YES;
            else if (status != Z_OK) break;
        }
        if (inflateEnd (&strm) != Z_OK) return nil;
    
        // Set real length.
        if (done)
        {
            [decompressed setLength: strm.total_out];
            return [NSData dataWithData: decompressed];
        }
        else return nil;
    }
    
    - (NSData *)gzipDeflate:(NSData*)data
    {
        if ([data length] == 0) return data;
    
        z_stream strm;
    
        strm.zalloc = Z_NULL;
        strm.zfree = Z_NULL;
        strm.opaque = Z_NULL;
        strm.total_out = 0;
        strm.next_in=(Bytef *)[data bytes];
        strm.avail_in = [data length];
    
        // Compresssion Levels:
        //   Z_NO_COMPRESSION
        //   Z_BEST_SPEED
        //   Z_BEST_COMPRESSION
        //   Z_DEFAULT_COMPRESSION
    
        if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) return nil;
    
        NSMutableData *compressed = [NSMutableData dataWithLength:16384];  // 16K chunks for expansion
    
        do {
    
            if (strm.total_out >= [compressed length])
                [compressed increaseLengthBy: 16384];
    
            strm.next_out = [compressed mutableBytes] + strm.total_out;
            strm.avail_out = [compressed length] - strm.total_out;
    
            deflate(&strm, Z_FINISH);  
    
        } while (strm.avail_out == 0);
    
        deflateEnd(&strm);
    
        [compressed setLength: strm.total_out];
        return [NSData dataWithData:compressed];
    }
    

    From the log:

    [data length] (orig):989631
    [data length] (gz):  102757
    [data length] (ungz):989631
    
    0 讨论(0)
  • 2020-12-14 12:05

    In iOS 13 and macOS 10.15 or newer you can use the new compressed method of NSData:

    let compressedData = try? NSData(data: data).compressed(using: .zlib)
    

    Unfortunately this method hasn't been ported to Swift's native Data class, but NSData can be simply casted to Data by adding as Data after the above code line.

    0 讨论(0)
  • 2020-12-14 12:07

    Swift 3 ready wrapper around libcompression. https://github.com/mw99/DataCompression

    Swift libcompression wrapper as an extension for the Data type (ZLIB, LZFSE, LZMA, LZ4, deflate, RFC-1950, RFC-1951)

    Interesting to play with in the playground: playground compression rates

    0 讨论(0)
  • 2020-12-14 12:10

    Yes, compress the data with zlib.

    @Brad Larson posted on this: see here and added the code as well.

    There is a CocoaPod which uses Objective-Zip by flyingdolphinstudio.

    0 讨论(0)
  • 2020-12-14 12:10

    Starting with iOS 9.0, there is built-in support for a few more compression algorithms. The library is called libcompression and supports LZ4, LZMA, ZLIB and LZFSE.

    Here’s a Swift example of using libcompression to decompress LZMA. It’s verbose, but avoids external dependencies and could be hidden in an extension on NSData.

    import Compression
    
    let streamPtr = UnsafeMutablePointer<compression_stream>.alloc(1)
    var stream = streamPtr.memory
    var status: compression_status
    
    status = compression_stream_init(&stream, COMPRESSION_STREAM_DECODE, COMPRESSION_LZMA)
    stream.src_ptr = UnsafePointer<UInt8>(compressedData.bytes)
    stream.src_size = compressedData.length
    
    let dstBufferSize: size_t = 4096
    let dstBufferPtr = UnsafeMutablePointer<UInt8>.alloc(dstBufferSize)
    stream.dst_ptr = dstBufferPtr
    stream.dst_size = dstBufferSize
    
    let decompressedData = NSMutableData()
    
    repeat {
        status = compression_stream_process(&stream, 0)
        switch status {
        case COMPRESSION_STATUS_OK:
            if stream.dst_size == 0 {
                decompressedData.appendBytes(dstBufferPtr, length: dstBufferSize)
                stream.dst_ptr = dstBufferPtr
                stream.dst_size = dstBufferSize
            }
        case COMPRESSION_STATUS_END:
            if stream.dst_ptr > dstBufferPtr {
                decompressedData.appendBytes(dstBufferPtr, length: stream.dst_ptr - dstBufferPtr)
            }
        default:
            break
        }
    }
    while status == COMPRESSION_STATUS_OK
    
    compression_stream_destroy(&stream)
    
    if status == COMPRESSION_STATUS_END {
        // Decompression succeeded, do something with decompressedData
    }
    else {
        // Decompression failed
    }
    
    0 讨论(0)
  • 2020-12-14 12:11

    Try this: https://github.com/mattt/Godzippa It was helpful for me.

    0 讨论(0)
提交回复
热议问题