• iOS LZMA类压缩算法使用


    LZMA(Lempel-Ziv-Markov chain-Algorithm的缩写)是2001年以来得到发展的一个数据压缩算法,它用于7-Zip归档工具中的7z格式和 Unix-like 下的 xz 格式。它使用类似于LZ77字典编码机制,在一般的情况下压缩率比bzip2为高,用于压缩的字典文件大小可达4GB。

    C++语言写成的LZMA开放源码压缩库使用了区间编码支持的LZ77改进压缩算法以及特殊的用于二进制的预处理程序。LZMA 对数据流、重复序列大小以及重续序列位置单独进行了压缩。LZMA支持几种散列链变体、二叉树以及基数树作为它的字典查找算法基础。

    LZMA算法引入

    对于数据传输,传输时间和传输质量是主要的两个参考维度。对于传输时间的压缩,数据压缩又是一个很好地可选项。目前正在处理蓝牙BLE(Bluetooth low energy(Bluetooth LE, BLE, marketed as Bluetooth Smart[1]))调试,其中数据传输过程中,发现由于速度限制,传输时间较长,为了缩短传输时间,想利用压缩算法对所要传输的数据进行压缩处理后再进行传输,压缩完成之后再进行传输,以提高传输效率及节省传输时间。经过查阅各种资料,初步使用LZMA压缩算法进行压缩。

    之所以选择LZMA算法进行压缩处理,原因有以下几点:

    • 开源
    • iOS & Android平台均支持,可夸平台使用
    • 使用广泛稳定,7zip即采用该算法及衍生算法
    • 压缩效率较高
    • 多线程支持

    iOS引入使用LZMA压缩算法方法

    选项1. 利用系统默认支持的LZMA压缩算法

    Apple提供了一套通用的无损压缩算法,其中就支持LZMA、LZMA2压缩.

    The libcompression library provides an API for two styles of data compression:

    • Block compression, where all of the input data is compressed or decompressed by one call to the compression or decompression function.
    • Streaming compression, where the compression or decompression function is called repeatedly to compress or decompress data from a source buffer to a destination buffer. Between calls, processed data is moved out of the destination buffer and new data is loaded into the source buffer.
    支持的压缩类型
    • Block Compression
    • Stream Compression
    支持的平台如下:
    • iOS 9.0+
    • macOS 10.11+
    • tvOS 9.0+
    • watchOS 2.0+
    支持的压缩算法
    • COMPRESSION_LZ4
    • COMPRESSION_ZLIB
    • COMPRESSION_LZMA
    • COMPRESSION_LZFSE

    提供的代码调用很简单,我根据我的需要,所使用的方法如下:

    压缩算法

    size_t compression_encode_buffer(uint8_t *restrict dst_buffer, size_t dst_size, const uint8_t *restrict src_buffer, size_t src_size, void *restrict scratch_buffer, compression_algorithm algorithm);

    解压方法

    size_t compression_decode_buffer(uint8_t *restrict dst_buffer, size_t dst_size, const uint8_t *restrict src_buffer, size_t src_size, void *restrict scratch_buffer, compression_algorithm algorithm);

    详细的调用代码如下

    - (void)testLZMA {
        // Data source file path.
        NSString *sourceFilePath = [NSString stringWithFormat:@"%@/source_data.txt", SYSTEM_DOCUMENT_PATH];
        // Compressed file path.
        NSString *zipFilePath = [NSString stringWithFormat:@"%@/compressed_data.7z", SYSTEM_DOCUMENT_PATH];
    
        NSData *fileData = [NSData dataWithContentsOfFile:sourceFilePath];
        DDLogDebug(@"Before compress: %ld bytes", fileData.length);
    
        uint8_t dstBuffer[fileData.length];
        memset(dstBuffer, 0, fileData.length);
    
        size_t compressResultLength = compression_encode_buffer(dstBuffer, fileData.length, [fileData bytes], fileData.length, NULL, COMPRESSION_LZMA);
        if(compressResultLength > 0) {
            NSData *dataAfterCompress = [NSData dataWithBytes:dstBuffer length:compressResultLength];
            DDLogDebug(@"Compress successfully. After compress:%ld bytes", dataAfterCompress.length;
            // Write compressed data into file.
            [dataAfterCompress writeToFile:zipFilePath atomically:YES];
        } else {
            DDLogError(@"Compress FAILED!!!");
        }
    }

    该方法集成使用起来非常简单,对于基本的压缩需求足够可以满足,且不会对App的大小造成太大影响,不会很大增加,如果没有特殊需求,该方法是首选。

    选项2. 集成第三方库LzmaSDKOjbcFramework

    这是我最先走的一条路,通过查阅相关资料,引入相关的开源库,自己实现了一个支持LZMA压缩算法的iOS工程用于Build Framework,现已开源到Github上,即LzmaSDKOjbcFramework

    虽然最终采用的方案一,但在制作LzmaSDKOjbcFramework过程中,也有一些收获,现分享给大家,愿对大家有些帮助。

    最初找到的LZMA的iOS支持库是 LzmaSDKObjC,但是这个库在引入开发工程中过程中,由于使用的cocoaPods, 必须使用use_frameworks! 才可以使用,但是由于podfile中存在其他引入的第三方库,这些库不适用use_frameworks!限制。

    此时陷入两难境地,使用use_frameworks!导致其他不支持framework的库不可用,如果不使用,LzmaSDKObjC则会报如下错误:

    Codec was not compiled in or stripped by static linking. 
    Make sure you are using 'use_frameworks!' and/or dynamic linking ...

    而CocoaPods又不支持针对某一第三方库来规定使用use_frameworks!

    既然这样,我打算自己创建一个iOS Framework工程开源,供团队内部及所有人方便使用。

    使用步骤

    Step1

    LzmaSDKOjbcFramework工程目录下,由于工程需要Inlineobjc库,所以使用CocoaPods进行安装,命令行执行如下命令:

    $ pod install
    Step2

    打开workspace工程文件,xCode中看到的内容如下:


    img
    Step3

    Archive工程并导出LzmaSDKObjC.framework文件到所需的工程路径下使用,使用如下:

    - (void)testLZMA {
        NSString *sourceFilePath = [NSString stringWithFormat:@"%@/source_data.txt", SYSTEM_DOCUMENT_PATH];
        NSString *zipFilePath = [NSString stringWithFormat:@"%@/compressed_data.7z", SYSTEM_DOCUMENT_PATH];
        DDLogDebug(@"
    
     ********** LZMA ********** 
    Src File: %@
    7Zip File:%@
    
    ", sourceFilePath, zipFilePath);
        // Create writer
        LzmaSDKObjCWriter * writer = [[LzmaSDKObjCWriter alloc] initWithFileURL:[NSURL fileURLWithPath:zipFilePath]];
    
        // Add file data's or paths
    //    [writer addData:[NSData ...] forPath:@"MyArchiveFileName.txt"]; // Add file data
        [writer addPath:sourceFilePath forPath:@"."]; // Add file at path
    //    [writer addPath:@"/Path/SomeDirectory" forPath:@"SomeDirectory"]; // Recursively add directory with all contents
    
        // Setup writer
        writer.delegate = self; // Track progress
    //    writer.passwordGetter = ^NSString*(void) { // Password getter
    //        return @"1234";
    //    };
    
        // Optional settings
        writer.method = LzmaSDKObjCMethodLZMA; // or LzmaSDKObjCMethodLZMA
        writer.solid = YES;
        writer.compressionLevel = 7;
        writer.encodeContent = YES;
        writer.encodeHeader = YES;
        writer.compressHeader = YES;
        writer.compressHeaderFull = YES;
        writer.writeModificationTime = NO;
        writer.writeCreationTime = NO;
        writer.writeAccessTime = NO;
    
        // Open archive file
        NSError * error = nil;
        [writer open:&error];
    
        // Write archive within current thread
        [writer write];
    }

    该方式的优点是支持的可选项较广,可以广泛的定制各种参数,但缺点是导入库后会导致应用包的体积变大,所以需要根据自身需求来选择。

    ENJOY.

  • 相关阅读:
    JavaScript事件处理
    JavaScript模拟"类"的三种方法
    非构造函数的继承和拷贝
    构造函数的继承
    vim开发环境
    socket之非阻塞
    网络编程
    多线程
    消息队列
    信号
  • 原文地址:https://www.cnblogs.com/tangyuanby2/p/7133443.html
Copyright © 2020-2023  润新知