Windows最新压缩API的C#实现

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档Windows


前言

许多应用程序都需要使用无损的数据压缩和解压缩。 Windows压缩 API 通过公共 API 公开 Windows 压缩算法来简化此功能。C#可以调用这些API实现流和文件的加压和解压。不支持Windows XP/Windows 7, 支持Windows 8/10/11.

一、支持算法如下:

XPRESS
XPRESS Huffman
MSZIP
LZMS

主要函数:
BOOL CreateCompressor(
[in] DWORD Algorithm,
[in, optional] PCOMPRESS_ALLOCATION_ROUTINES AllocationRoutines,
[out] PCOMPRESSOR_HANDLE CompressorHandle
);
BOOL Compress(
[in] COMPRESSOR_HANDLE CompressorHandle,
[in] LPCVOID UncompressedData,
[in] SIZE_T UncompressedDataSize,
[out] PVOID CompressedBuffer,
[in] SIZE_T CompressedBufferSize,
[out] PSIZE_T CompressedDataSize
);
BOOL CloseCompressor(
[in] COMPRESSOR_HANDLE CompressorHandle
);

其他详情参阅微软:http://msdn.microsoft.com/en-us/library/hh968104(v=vs.85).aspx

二、C# 实现代码

1.压缩

    int compressXpress(byte[] InputBuffer, int size, ref IntPtr CompressedBuffer, out string err) 
    //  CompressedBuffer需要提前分配内存空间(非托管), 可为size的两倍。
    {
        System.IntPtr Compressor = System.IntPtr.Zero;
        err = "";

        try
        {
            unsafe
            {
                System.Int32 Success;
                System.UInt32 CompressedBufferSize;
                System.UInt32 CompressedDataSize = 0;

                //  Create an XpressHuff compressor.
                Success = CreateCompressor(
                    COMPRESS_ALGORITHM_XPRESS, //  Compression Algorithm
                     System.IntPtr.Zero,
                     out Compressor);

                if (Success == 0)
                {
                    err = "Create fail! ";
                    int errCode = Marshal.GetLastWin32Error();
                    err += GetSysErrMsg(errCode);
                    return -2;
                }

                // byte* memBytePtr = (byte*)CompressedBuffer.ToPointer();
                // for (int i = 0; i < 100; i++) testBytes[i] = memBytePtr[i];

                //  Query compressed buffer size.
                Success = Compress(
                    Compressor,                  //  Compressor Handle
                    InputBuffer,                 //  Input buffer, Uncompressed data
                    (uint)size,               //  Uncompressed data size
                    CompressedBuffer,                        //  Compressed Buffer
                    0,                           //  Compressed Buffer size
                    out CompressedBufferSize);      //  Compressed Data size

                if (CompressedBufferSize == 0)
                {
                    err = "Query fail! BufferSize = 0";
                    return -3;
                }

                //  Call Compress() again to do real compression and output the compressed
                //  data to CompressedBuffer.
                Success = Compress(
                    Compressor,             //  Compressor Handle
                    InputBuffer,            //  Input buffer, Uncompressed data
                    (uint)size,          //  Uncompressed data size
                    CompressedBuffer,       //  Compressed Buffer
                    CompressedBufferSize,   //  Compressed Buffer size
                    out CompressedDataSize);   //  Compressed Data size

                if (Success == 0)
                {
                    err = "Execution fail! ";
                    int errCode = Marshal.GetLastWin32Error();
                    err += GetSysErrMsg(errCode);
                    return -4;
                }

                //memBytePtr = (byte*)CompressedBuffer.ToPointer();
                //for (int i = 0; i < 100; i++) testBytes[i] = memBytePtr[i];

                return (int)CompressedDataSize;
            }

        }
        catch (Exception ex)
        {
            err = "Function exception: " + ex.Message;
            return -1;
        }
        finally
        {
            try
            {
                if (Compressor != System.IntPtr.Zero)
                {
                    CloseCompressor(Compressor);
                }

            }
            catch { }
        }
    }

2.解压缩

   int decompressXpress(byte[] InputBuffer, int size, out byte[] outdata, out string err)
    {
        System.IntPtr deCompressor = System.IntPtr.Zero;
        IntPtr deCompressedBuffer = System.IntPtr.Zero;
        err = "";
        outdata = new byte[0];

        if (InputBuffer.Length == 0) return 0;

        try
        {
            unsafe
            {
                System.Int32 Success;
                System.UInt32 deCompressedBufferSize;
                System.UInt32 deCompressedDataSize = 0;

                //  Create an XpressHuff compressor.
                Success = CreateDecompressor(
                    COMPRESS_ALGORITHM_XPRESS, //  Compression Algorithm
                     System.IntPtr.Zero,
                     out deCompressor);

                if (Success == 0)
                {
                    err = "Create fail! ";
                    int errCode = Marshal.GetLastWin32Error();
                    err += GetSysErrMsg(errCode);
                    return -2;
                }

                //  byte* memBytePtr = (byte*)CompressedBuffer.ToPointer();
                // for (int i = 0; i < 100; i++) testBytes[i] = memBytePtr[i];

                //  Query compressed buffer size.
                Success = Decompress(
                    deCompressor,                  //  Compressor Handle
                    InputBuffer,                 //  Input buffer, Uncompressed data
                    (uint)size,               //  Uncompressed data size
                    deCompressedBuffer,                        //  Compressed Buffer
                    0,                           //  Compressed Buffer size
                    out deCompressedBufferSize);      //  Compressed Data size

                if (deCompressedBufferSize == 0)
                {
                    err = "Query fail! BufferSize = 0";
                    return -3;
                }

                / 分配内存
                try
                {
                    deCompressedBuffer = System.Runtime.InteropServices.Marshal.AllocHGlobal((int)deCompressedBufferSize);
                }
                catch (Exception ex)
                {
                    this.Invoke(new EventHandler(delegate
                    {
                        MessageBox.Show(deCompressedBufferSize + " - AllocHGlobal失败:" + ex.Message);
                        throw new Exception(ex.Message);
                    }));
                }

                //  Call Compress() again to do real compression and output the compressed
                //  data to CompressedBuffer.
                Success = Decompress(
                    deCompressor,             //  Compressor Handle
                    InputBuffer,            //  Input buffer, Uncompressed data
                    (uint)size,          //  Uncompressed data size
                    deCompressedBuffer,       //  Compressed Buffer
                    deCompressedBufferSize,   //  Compressed Buffer size
                    out deCompressedDataSize);   //  Compressed Data size

                if (Success == 0 || deCompressedDataSize == 0)
                {
                    err = "Execution fail! ";

                    if (Success == 0)
                    {
                        int errCode = Marshal.GetLastWin32Error();
                        err += GetSysErrMsg(errCode);
                    }
                    else
                    {
                        err += "解压返回数据长度为0.";
                    }

                    return -4;
                }

                outdata = new byte[deCompressedDataSize];
                byte* memBytePtr = (byte*)deCompressedBuffer.ToPointer();
                for (int i = 0; i < deCompressedDataSize; i++) outdata[i] = memBytePtr[i];

                return (int)deCompressedDataSize;
            }

        }
        catch (Exception ex)
        {
            err = "Function exception: " + ex.Message;
            return -1;
        }
        finally
        {
            try
            {
                unsafe // free mem
                {
                    if (deCompressedBuffer != null && deCompressedBuffer != IntPtr.Zero) System.Runtime.InteropServices.Marshal.FreeHGlobal(deCompressedBuffer);
                }
            }
            catch { }

            try
            {
                if (deCompressor != System.IntPtr.Zero)
                {
                    CloseDecompressor(deCompressor);
                }

            }
            catch { }
        }
    }

3.取错误代码描述

    [System.Runtime.InteropServices.DllImport("Kernel32.dll")]
    public extern static int FormatMessage(int flag, ref IntPtr source, int msgid, int langid, ref string buf, int size, ref IntPtr args);

    /// <summary>
    /// 获取系统错误信息描述
    /// </summary>
    /// <param name="errCode">系统错误码</param>
    /// <returns></returns>
    public static string GetSysErrMsg(int errCode)
    {
        IntPtr tempptr = IntPtr.Zero;
        string msg = null;
        FormatMessage(0x1300, ref tempptr, errCode, 0, ref msg, 255, ref tempptr);
        return msg;
    }

4.函数c#说明

    /*

#define COMPRESS_ALGORITHM_INVALID 0
#define COMPRESS_ALGORITHM_NULL 1
#define COMPRESS_ALGORITHM_MSZIP 2
#define COMPRESS_ALGORITHM_XPRESS 3
#define COMPRESS_ALGORITHM_XPRESS_HUFF 4
#define COMPRESS_ALGORITHM_LZMS 5
#define COMPRESS_ALGORITHM_MAX 6
*/

    const int COMPRESS_ALGORITHM_XPRESS = 3; //COMPRESS_ALGORITHM_XPRESS_HUFF

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate System.UInt32 PFN_COMPRESS_ALLOCATE(System.UInt32 UserContext, System.UInt32 Size);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void PFN_COMPRESS_FREE(System.UInt32 UserContext, System.UInt32 Memory);

    [StructLayout(LayoutKind.Sequential)]
    public struct COMPRESS_ALLOCATION_ROUTINES
    {
        public PFN_COMPRESS_ALLOCATE Allocate;
        public PFN_COMPRESS_FREE Free;
        public System.UInt32 UserContext;
    }

    [DllImport("Cabinet.dll", SetLastError = true)]

    public static extern System.Int32 CreateCompressor(
        System.UInt32 Algorithm,
        System.IntPtr AllocationRoutines,
        out System.IntPtr CompressorHandle
    );
    
    [DllImport("Cabinet.dll", SetLastError = true)]
    public static extern System.Int32 CreateDecompressor(
        System.UInt32 Algorithm,
        System.IntPtr AllocationRoutines,
        out System.IntPtr DecompressorHandle
    );

    [DllImport("Cabinet.dll", SetLastError = true)]
    public static extern System.Int32 Compress(
    System.IntPtr CompressorHandle,
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]byte[] UncompressedData,
    System.UInt32 UncompressedDataSize,
    IntPtr CompressedBuffer,
    System.UInt32 CompressedBufferSize,
    out System.UInt32 CompressedDataSize
    );

    [DllImport("Cabinet.dll", SetLastError = true)]
    public static extern System.Int32 Decompress(
    System.IntPtr DecompressorHandle,
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]byte[] CompressedData,
    System.UInt32 CompressedDataSize,
    IntPtr UncompressedBuffer,
    System.UInt32 UncompressedBufferSize,
    out System.UInt32 UncompressedDataSize
    );


    [DllImport("Cabinet.dll", SetLastError = true)]
    public static extern System.Int32 CloseCompressor(
      System.IntPtr CompressorHandle
    );


    [DllImport("Cabinet.dll", SetLastError = true)]
    public static extern System.Int32 CloseDecompressor(
      System.IntPtr DecompressorHandle
    );

总结

Xpress压缩率和Windows的NTFS文件压缩率差不多, 速度很快, 我的机器上有300MB/s,
XPRESS Huffman压缩率要高10%的样子,速度大概150MB/s.

C#也有包装好的GZIP压缩类,压缩率稍微高于XPRESS Huffman(3%-5%),速度较慢,我的机器上快速模式大概60MB/s.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ni-488.2 version 2.3 for windows.zip是一种针对Windows操作系统的NI-488.2版本2.3的软件压缩文件。 NI-488.2是一种通用接口规范,用于控制和通信与仪器设备的硬件连接。与许多科学、工程以及实验室应用相关的仪器和设备,如电子测量设备、仪器控制设备等,通常需要通过一种专用接口与计算机进行交互。 这个压缩文件包含了NI-488.2规范的第2.3版本的安装程序。安装这个软件可以让您的Windows系统与符合NI-488.2规范的设备进行通信和控制。 安装这个软件可能需要一定的计算机操作和设置。一旦完成安装,您就可以使用开发工具、编程语言或相关软件包来编写控制程序,以控制您所连接的仪器设备。 NI-488.2 version 2.3 for windows.zip是NI公司提供的软件压缩包,可能需要在其官方网站上下载安装。在下载和安装软件之前,建议先参考官方文档和用户指南,以了解其使用方法和要求。 总之,NI-488.2 version 2.3 for windows.zip是一种用于Windows系统的软件压缩文件,安装后可以实现您的计算机与符合NI-488.2规范的仪器设备的通信和控制。 ### 回答2: ni-488.2 version 2.3 for windows.zip是一种用于Windows操作系统的软件压缩包。它是用于与仪器进行通信的国际标准通信库,特别适用于使用GPIB(通用仪器总线)进行通信的设备。 该软件压缩包包含了版本为2.3的ni-488.2软件。安装这个软件可以使计算机和与GPIB通信的仪器之间建立连接和数据传输。这样,用户就可以通过计算机来控制和监测仪器的运行状态,以及实现数据的采集和处理。 ni-488.2 version 2.3 for windows.zip的安装步骤通常为:首先解压缩该文件,然后运行安装程序。在安装过程中,可能需要输入一些相关的设置和选项,如GPIB接口的地址、仪器的型号和序列号等。 安装完成后,该软件将会添加到用户的计算机中,用户可以通过使用提供的API(应用程序编程接口)来编写与仪器进行通信的程序。这些程序可以在编程语言中实现,如LabVIEW、C++、C#等。 总之,ni-488.2 version 2.3 for windows.zip是一种用于Windows操作系统的GPIB通信软件,它提供了与仪器进行通信的便捷方式,帮助用户控制和监控仪器,并实现数据的采集和处理。 ### 回答3: ni-488.2 version 2.3 for windows.zip是一个用于Windows操作系统的NI-488.2版本2.3的压缩文件。NI-488.2是一种用于GPIB通信的软件库,用于控制和与测量设备进行数据交换。这个压缩文件包含了安装NI-488.2 v2.3所需的所有文件和文档。 要使用这个压缩文件,您首先需要解压缩它。您可以右键单击该zip文件并选择"提取到指定文件夹",然后选择一个目标文件夹将其中的文件提取出来。 一旦解压缩完成,您可以打开解压后的文件夹,里面应该包含安装程序和其他必要的文件。双击运行安装程序,按照提示进行安装。安装程序会将NI-488.2软件和所需的驱动程序安装到您的计算机上。 安装完成后,您可以根据您的需要来使用NI-488.2。您可以使用该软件库来编写程序,控制GPIB设备,并获取所需的数据。此外,NI-488.2还提供了文档和示例代码,您可以根据需要进行参考和学习。 总而言之,ni-488.2 version 2.3 for windows.zip是一个用于Windows操作系统的NI-488.2版本2.3的压缩文件,包含安装文件和文档。通过解压缩、安装和使用该软件库,您可以控制和与GPIB设备进行数据交换。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值