C#编程总结(十三)数据压缩

C#编程总结(十三)数据压缩

在进行文件存储或者数据传输时,为了节省空间流量,需要对数据或文件进行压缩。在这里我们讲述通过C#实现数据压缩。

一、GZipStream压缩

微软提供用于压缩和解压缩流的方法。

此类表示 GZip 数据格式,它使用无损压缩和解压缩文件的行业标准算法。 这种格式包括一个检测数据损坏的循环冗余校验值。 GZip 数据格式使用的算法与 DeflateStream 类的算法相同,但它可以扩展以使用其他压缩格式。 这种格式可以通过不涉及专利使用权的方式轻松实现。

可以使用许多常见的压缩工具对写入到扩展名为 .gz 的文件的压缩 GZipStream 对象进行解压缩;但是,此类原本并不提供用于向 .zip 存档中添加文件或从 .zip 存档中提取文件的功能。

DeflateStream 和 GZipStream 中的压缩功能作为流公开。 由于数据是以逐字节的方式读取的,因此无法通过进行多次传递来确定压缩整个文件或大型数据块的最佳方法。 对于未压缩的数据源,最好使用 DeflateStream 和 GZipStream 类。 如果源数据已压缩,则使用这些类时实际上可能会增加流的大小。

具体实现源码

1、压缩字节数组

        /// <summary>
        /// 压缩字节数组
        /// </summary>
        /// <param name="str"></param>
        public static byte[] Compress(byte[] inputBytes)
        {
            using (MemoryStream outStream = new MemoryStream())
            {
                using (GZipStream zipStream = new GZipStream(outStream, CompressionMode.Compress, true))
                {
                    zipStream.Write(inputBytes, 0, inputBytes.Length);
                    zipStream.Close(); //很重要,必须关闭,否则无法正确解压
                    return outStream.ToArray();
                }
            }
        }

        /// <summary>
        /// 解压缩字节数组
        /// </summary>
        /// <param name="str"></param>
        public static byte[] Decompress(byte[] inputBytes)
        {

            using (MemoryStream inputStream = new MemoryStream(inputBytes))
            {
                using (MemoryStream outStream = new MemoryStream())
                {
                    using (GZipStream zipStream = new GZipStream(inputStream, CompressionMode.Decompress))
                    {
                        zipStream.CopyTo(outStream);
                        zipStream.Close();
                        return outStream.ToArray();
                    }
                }

            }
        }

2、压缩字符串

在压缩字节的基础扩展而来,注意字符转换,保证不出现乱码。具体原理,这里不再介绍,可见:

C#编程总结(十)字符转码 http://www.cnblogs.com/yank/p/3536863.html

        /// <summary>
        /// 压缩字符串
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string Compress(string input)
        {
            byte[] inputBytes = Encoding.Default.GetBytes(input);
            byte[] result = Compress(inputBytes);
            return Convert.ToBase64String(result);
        }
        /// <summary>
        /// 解压缩字符串
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string Decompress(string input)
        {
            byte[] inputBytes = Convert.FromBase64String(input);
            byte[] depressBytes = Decompress(inputBytes);
            return Encoding.Default.GetString(depressBytes);
        }

3、压缩文件

如果你试图自己做一个压缩工具,相比这个方法很管用

        /// <summary>
        /// 压缩目录
        /// </summary>
        /// <param name="dir"></param>
        public static void Compress(DirectoryInfo dir)
        {
            foreach (FileInfo fileToCompress in dir.GetFiles())
            {
                Compress(fileToCompress);
            }
        }
        /// <summary>
        /// 解压缩目录
        /// </summary>
        /// <param name="dir"></param>
        public static void Decompress(DirectoryInfo dir)
        {
            foreach (FileInfo fileToCompress in dir.GetFiles())
            {
                Decompress(fileToCompress);
            }
        }
        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="fileToCompress"></param>
        public static void Compress(FileInfo fileToCompress)
        {
            using (FileStream originalFileStream = fileToCompress.OpenRead())
            {
                if ((File.GetAttributes(fileToCompress.FullName) & FileAttributes.Hidden) != FileAttributes.Hidden & fileToCompress.Extension != ".gz")
                {
                    using (FileStream compressedFileStream = File.Create(fileToCompress.FullName + ".gz"))
                    {
                        using (GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionMode.Compress))
                        {
                            originalFileStream.CopyTo(compressionStream);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 解压缩文件
        /// </summary>
        /// <param name="fileToDecompress"></param>
        public static void Decompress(FileInfo fileToDecompress)
        {
            using (FileStream originalFileStream = fileToDecompress.OpenRead())
            {
                string currentFileName = fileToDecompress.FullName;
                string newFileName = currentFileName.Remove(currentFileName.Length - fileToDecompress.Extension.Length);

                using (FileStream decompressedFileStream = File.Create(newFileName))
                {
                    using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
                    {
                        decompressionStream.CopyTo(decompressedFileStream);
                    }
                }
            }
        }

二、开源组件ICSharpCode.SharpZipLib进行压缩

ICSharpCode.SharpZipLib,开源组件,支持Zip,GZip,BZip2,Tar等

其压缩效率及压缩比比微软自带的要好。并提供了源码,开源对其算法进行研究、改进。具体可见:

http://www.icsharpcode.net/OpenSource/SharpZipLib/

这里提供简单的一种实现以供参考,其他算法比较类似,不再赘述。

1、使用BZip2压缩字符串

        /// <summary>
        /// 压缩
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string Compress(string input)
        {
            string result = string.Empty;
            byte[] buffer = Encoding.UTF8.GetBytes(input);
            using (MemoryStream outputStream = new MemoryStream())
            {
                using (BZip2OutputStream zipStream = new BZip2OutputStream(outputStream))
                {
                    zipStream.Write(buffer, 0, buffer.Length);
                    zipStream.Close();
                }
                return Convert.ToBase64String(outputStream.ToArray());
            }
        }
        /// <summary>
        /// 解压缩
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string Decompress(string input)
        {
            string result = string.Empty;
            byte[] buffer = Convert.FromBase64String(input);
            using (Stream inputStream = new MemoryStream(buffer))
            {
                BZip2InputStream zipStream = new BZip2InputStream(inputStream);

                using (StreamReader reader = new StreamReader(zipStream, Encoding.UTF8))
                {
                    //输出
                    result = reader.ReadToEnd();
                }
            }

            return result;
        }

三、Demo下载地址

http://files.cnblogs.com/yank/CompressSample.zip

四、后续

如有其他更好的压缩方法,请指出。后续会更新至此。

时间: 2024-10-08 08:10:56

C#编程总结(十三)数据压缩的相关文章

【读书笔记】C#高级编程 第十三章 异步编程

(一)异步编程的重要性 使用异步编程,方法调用是在后台运行(通常在线程或任务的帮助下),并不会阻塞调用线程.有3中不同的异步编程模式:异步模式.基于事件的异步模式和新增加的基于任务的异步模式(TAP,可利用async和await关键字来实现). (二)异步模式 1.C#1的APM 异步编程模型(Asynchronous Programming Model). 2.C#2的EAP 基于事件的异步模式(Event-based Asynchronous Pattern). 3.TAP 基于任务的异步模

java 面向对象编程-- 第十三章 反射、类加载与垃圾回收

1.狭义JavaBean规范 Javabean必须包含一个无参数的public构造方法,方便通过反射的方式产生对象. 属性必须都是私有的. Javabean必须包含符合命名规范的get和set方法,以便访问Javabean的属性. Javabean应该是可序列化(serializable)的. 2.反射 在编译时,并不清楚应该加载哪个类.类的加载是在运行期间进行的.通过反射,可以对类进行加载.探知.自审. 可以通过对象.getClass()或者通过类名.class或者通过Class.forNam

C#高级编程四十三天----Lambda表达式

Lambda表达式 案例: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace lambda表达式 { class Program { public delegate int del(int i); static void Main(string[] args) { List<string> fr

C#高级编程五十三天----字典Dictionary&lt;TKey,TValue&gt;

字典 关键字:Dicitionary 说明: 必须包含命名空间System.Collection.Generic Dictionary里面的每一个元素都是一个键值对(由两个元组组成:键和值). 键必须是唯一的,而值不需要唯一的. 键和值都可以是任意类型(例如:string,int,自定义类型,等等) 通过一个键读取一个值的事件是接近O(1) 键值对之间的偏序可以不定义 使用案例: using System; using System.Collections.Generic; using Syst

C#高级编程六十三天----并行LINQ

并行LINQ .NET4在System.Linq命名空间中包含一个新类ParallelEnumerable,可以分解查询的工作使其分布在多个线程上.尽管Enumerable类给IEnumerable<T>接口定义了扩展方法,但ParallelEnumerable类的大多数扩展方法是ParallelQuery<TSource>类的扩展.一个重要的例外是AsParallel()方法,它扩展了IEnumerable<TSource>接口,返回ParallelQuery<

鸡啄米:C++编程之十三学习之类与对象,类的声明,成员的访问控制

1. 本次学习鸡啄米课程第13篇,把比较重要的学习记录下来,以敦促自己更好的学习.推荐他们的网址学习:http://www.jizhuomi.com/school/c/97.html 2. 在面向过程的设计中,程序的模块是函数构成的,而面向对象设计中程序模块是类构成的,函数只是语句和数据的封装,而类是函数和数据的封装,做了一段C++之后,才明白这句话的意思.其实类就是一种自定义的数据类型.可以定义某个类类型的变量,用类定义的变量叫做类的对象,这种定义对象的过程叫做实例化. 3. 不过一直有个疑问

Linux Shell常用技巧(十二) Shell编程

Linux Shell常用技巧(十二) Shell编程 二十三. Bash Shell编程:  1.  读取用户变量:    read命令是用于从终端或者文件中读取输入的内建命令,read命令读取整行输入,每行末尾的换行符不被读入.在read命令后面,如果没有指定变量名,读取的数据将被自动赋值给特定的变量REPLY.下面的列表给出了read命令的常用方式: 命令格式 描述 read answer 从标准输入读取输入并赋值给变量answer. read first last 从标准输入读取输入到第

Linux网络编程视频 百度网盘

Linux网络编程(总共41集)讲解Linux网络编程知识,分以下四个篇章.Linux网络编程之TCP/IP基础篇Linux网络编程之socket编程篇Linux网络编程之进程间通信篇Linux网络编程之线程篇Linux网络编程之TCP/IP基础篇01TCPIP基础(一)ISO/OSI参考模型TCP/IP四层模型基本概念(对等通信.封装.分用.端口)02TCPIP基础(二)最大传输单元(MTU)/路径MTU以太网帧格式ICMPARPRARP03TCPIP基础(三)IP数据报格式网际校验和路由04

Windows界面编程第十二篇 位图显示特效 飞入效果与伸展效果

分享一下我老师大神的人工智能教程吧.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net 转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/8696726 欢迎关注微博:http://weibo.com/MoreWindows Windows界面编程之位图显示特效系列目录: 1. <Windows界面编程第九篇位图显示特效交错效果> http:/

Java精品高级课,架构课,java8新特性,P2P金融项目,程序设计,功能设计,数据库设计,第三方支付,web安全,视频教程

36套精品Java架构师,高并发,高性能,高可用,分布式,集群,电商,缓存,性能调优,设计模式,项目实战,P2P金融项目,大型分布式电商实战视频教程 视频课程包含: 高级Java架构师包含:Spring boot.Spring  cloud.Dubbo.Elasticsearch,Redis.ActiveMQ.Nginx.Mycat.Spring.MongoDB.ZeroMQ.Git.Nosql.Jvm.Mecached.Netty.Nio.Mina.java8新特性,P2P金融项目,程序设计,