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, , 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, , 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

四、后续

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

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

  1. 学习ASP.NET Core Razor 编程系列十三——文件上传功能(一)

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  2. 并发编程(十三)—— Java 线程池 实现原理与源码深度解析 之 Executors(三)

    前两篇文章讲了线程池的源码分析,再来看这篇文章就比较简单了, 本文主要讲解 Executors 这个工具类,看看长江创建线程池的几种方法. newFixedThreadPool 生成一个固定大小的线程 ...

  3. java并发编程(十三)----(JUC原子类)引用类型介绍(CAS和ABA的介绍)

    这一节我们将探讨引用类型原子类:AtomicReference, AtomicStampedRerence, AtomicMarkableReference.AtomicReference的使用非常简 ...

  4. 通过DatagramSocket实现UDP编程(十三)

    原文链接:https://www.cnblogs.com/hysum/p/7533149.html UDP通信: UDP协议(用户数据报协议)是无连接.不可靠.无序的. UDP协议以数据报作为数据传输 ...

  5. ~~并发编程(十三):信号量,Event,定时器~~

    进击のpython ***** 并发编程--信号量,Event,定时器 本节需要了解的就是: 信号量,以及信号量和互斥锁的区别 了解时间和定时器,以及使用 信号量 信号量也是锁,本质没有变!但是他跟互 ...

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

    (一)异步编程的重要性 使用异步编程,方法调用是在后台运行(通常在线程或任务的帮助下),并不会阻塞调用线程.有3中不同的异步编程模式:异步模式.基于事件的异步模式和新增加的基于任务的异步模式(TAP, ...

  7. java并发编程(十三)经典问题生产者消费者问题

    生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 这里实现如下情况的生产--消费模型: 生产者不断交替地生产两组数据&q ...

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

    1.狭义JavaBean规范 Javabean必须包含一个无参数的public构造方法,方便通过反射的方式产生对象. 属性必须都是私有的. Javabean必须包含符合命名规范的get和set方法,以 ...

  9. Java并发编程(十三)-- 线程池

    什么是线程池? 线程池就是以一个或多个线程循环执行多个应用逻辑的线程集合. 为什么用线程池? 创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率 例如: 记创建线程消耗时 ...

  10. python网络编程(十三)

    协程-greenlet版 为了更好使用协程来完成多任务,python中的greenlet模块对其封装,从而使得切换任务变的更加简单 安装方式 使用如下命令安装greenlet模块: sudo pip ...

随机推荐

  1. asp.net 验证码session为null的解决方案

    最近在做Y集团的订单系统时,登陆页面在测试时发现一个以前没有注意到的问题,登陆页面需要使用验证码,引用了一个生成验证码的aspx页面,在aspx页面中生成session和验证码图片,在登陆页面的后台处 ...

  2. ubuntu 13.04下MYSQL 5.5环境搭建

    解决的问题: 安装mysql server和mysql client 5.5 新建远程账户 远程访问权限 MYSQL默认字符集修改为UTF8 检查防火墙 一.安装 BTW:可以使用查找命令查看安装包 ...

  3. 12小时包你学会基于ReactMix框架的ReactNativeApp开发(二)基于Css+HTML写第一个app页面

    上一篇文章,大家对于ReactMix(https://github.com/xueduany/react-mix)框架有了一个基本认识,知道我们是一个语法糖,帮助大家基于一套代码,所有平台都能跑.那么 ...

  4. 大叔也说Xamarin~Android篇~原生登陆与WebView的网站如何共享Session

    回到目录 事情是这样的,我们最近开了一个APP,主要使用xamarin做了一个登陆,它与服务器API进行数据通讯,当用户名密码正确去,跳转到新的activity,并在webview控件中打开服务端的H ...

  5. Java线程:线程的交互

      一.线程交互的基础知识   SCJP所要求的线程交互知识点需要从java.lang.Object的类的三个方法来学习:    void notify()           唤醒在此对象监视器上等 ...

  6. 深度解析SDN——利益、战略、技术、实践(实战派专家力作,业内众多专家推荐)

    深度解析SDN——利益.战略.技术.实践(实战派专家力作,业内众多专家推荐) 张卫峰 编   ISBN 978-7-121-21821-7 2013年11月出版 定价:59.00元 232页 16开 ...

  7. fir.im Weekly - 深度揭秘 App 启动全过程

    世纪寒潮席卷全中国,可谓普天之下莫低0℃.无论怎样的严寒都抵挡不了程序员们的创造的激情... 本期的 fir.im Weekly ,最新的 iOS/Android 开发资源,GitHub 源码.前端技 ...

  8. JDBC操作数据库,第一:jsp插入mysql数据库,坎坷摸索分享

    JSP连接数据库,坎坷摸索了好久,现在终于做好了,分享一下,希望对更多热爱编程学习的人有所帮助!!!谢谢 第一:首先准备的就是已经安装好Mysql,这里不做多叙述,百度可以做到. 然后在mysql数据 ...

  9. Struts2学习笔记 - HelloWorld总结

    相信网上已经有很多关于struts2的HelloWorld可参考,我这里就不重复了,没个学struts2的人都会做过很多个HelloWorld,而我这里就总结一下一个简单的HelloWorld 我在一 ...

  10. 快速入门系列--WebAPI--01基础

    ASP.NET MVC和WebAPI已经是.NET Web部分的主流,刚开始时两个公用同一个管道,之后为了更加的轻量化(WebAPI是对WCF Restful的轻量化),WebAPI使用了新的管道,因 ...