ios 有没有实用的方法来压缩 NSData?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8425012/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:47:11  来源:igfitidea点击:

Is there a practical way to compress NSData?

iosnsdatadata-compression

提问by eric.mitchell

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

我还没有看到有关该主题的任何文档,但这并不意味着它不存在。

采纳答案by zaph

Yes, compress the data with zlib.

是的,用 zlib 压缩数据。

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

@Brad Larson 在此发布:请参阅此处并添加代码。

There is a CocoaPodwhich uses Objective-Zipby flyingdolphinstudio.

有一个CocoaPod,它使用了flydolphinstudio 的Objective-Zip

回答by Adriano Lucas

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

按照@Zaph 和@Brad Larson 的帖子,下面是两种方法gzipInflategzipDeflate它们可以很好地压缩/解压缩NSData。(从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

回答by jbg

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.

从 iOS 9.0 开始,内置了对更多压缩算法的支持。该库名为 libcompression,支持 LZ4、LZMA、ZLIB 和 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.

这是使用 libcompression 解压缩 LZMA 的 Swift 示例。它很冗长,但避免了外部依赖,并且可以隐藏在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
}

回答by Blake Watters

I have made a nice Objective-C BZip2 compression interface available as a CocoaPod: https://github.com/blakewatters/BZipCompression

我制作了一个不错的 Objective-C BZip2 压缩接口,可用作 CocoaPod:https: //github.com/blakewatters/BZipCompression

回答by LimeRed

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

围绕 libcompression 的 Swift 3 就绪包装器。 https://github.com/mw99/DataCompression

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

Swift libcompression 包装器作为数据类型的扩展(ZLIB、LZFSE、LZMA、LZ4、deflate、RFC-1950、RFC-1951)

Interesting to play with in the playground: playground compression rates

在操场上玩很有趣: 操场压缩率

回答by Ely

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

在 iOS 13 和 macOS 10.15 或更高版本中,您可以使用以下新compressed方法NSData

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

Unfortunately this method hasn't been ported to Swift's native Dataclass, but NSDatacan be simply casted to Databy adding as Dataafter the above code line.

不幸的是,此方法尚未移植到 Swift 的本机Data类,但NSData可以Data通过as Data在上述代码行之后添加来简单地转换为。

回答by ZevsVU

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

试试这个:https: //github.com/mattt/Godzippa这对我很有帮助。