2011-12-08 19 views
12

Tôi chưa thấy bất kỳ tài liệu nào về chủ đề này, nhưng điều đó không có nghĩa là nó không tồn tại.Có cách nào thực tế để nén NSData không?

+0

loại nén nào? zip thẳng? Bạn có thể lấy các byte từ nó và sử dụng thư viện zip – DanZimm

+4

Câu hỏi này hoàn toàn tương đương với "có thể nén dữ liệu không?" và câu trả lời rõ ràng là "có". –

+0

bản sao có thể có của [API nén trên iPhone] (http://stackoverflow.com/questions/230984/compression-api-on-the-iphone) –

Trả lời

5

Có, nén dữ liệu bằng zlib.

@ Brad Larson đăng trên: see here và thêm mã này.

Có một số CocoaPod sử dụng Objective-Zip bởi flyingdolphinstudio.

+0

Liên kết tốt- cảm ơn vì điều đó –

+1

Làm cách nào mà mọi người quản lý để đọc danh mục NSDataCategory đó trang (http://cocoadev.com/wiki/NSDataCategory)? Họ định dạng ở tất cả các mã này? – jkcl

+0

liên kết bị hỏng :-(.. bạn có thể vui lòng cập nhật nó không? – Devarshi

23

Theo dõi @Zaph & Bài đăng của @Brad Larson, bên dưới là 2 phương pháp gzipInflategzipDeflate hoạt động tốt để nén/giải nén NSData. (Mã định dạng lại từ 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]; 
} 

Từ nhật ký:

[data length] (orig):989631 
[data length] (gz): 102757 
[data length] (ungz):989631 
+0

Wow, điều này thật tuyệt! Cảm ơn –

+0

@Rayay nếu muốn sử dụng bzip2 thay vì gzip, hãy xem [bài đăng này] (http://stackoverflow.com/questions/9577735/how-compress-data-in-memory-buffer-by-using-libbz2-library -in-c-program/11390277 # 11390277). –

+0

Trông rất đẹp, nhưng khi biên dịch, Xcode nói _BZ2_bzCompressEnd và bạn bè là các ký hiệu không xác định cho armv7. –

8

Bắt đầu với iOS 9.0, có hỗ trợ tích hợp cho một vài thuật toán nén hơn. thư viện được gọi là libcompression và hỗ trợ LZ4, LZMA, ZLIB và LZFSE.

Dưới đây là ví dụ Swift về cách sử dụng tính năng nén để giải nén LZMA. Đó là tiết, nhưng tránh phụ thuộc bên ngoài và có thể bị ẩn trong phần mở rộng trên 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

Tiện ích mở rộng Swift trên NSData có thể tìm thấy tại đây: https://github.com/leemorgan/NSData-Compression – Klaas

+1

Tốt nhưng không vui khi chuyển đổi sang Swift 3 ... – Gujamin

Các vấn đề liên quan