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. 国外社交网站获取分享数量APIs

    之前有一篇文章详细介绍了如何获取网页在Facebook,Twitter和LinkedIn社交平台上分享的数量,点击这里查看.这里再扩充一下! Twitter GET URL: http://cdn.a ...

  2. ssl小结

    有几篇不错的文章: http://www.cnblogs.com/pen-ink/archive/2011/01/17/1937680.html 这个应该是最简单的示例了. 不过,当两个passwor ...

  3. 05- Shell脚本学习--函数

    函数可以让我们将一个复杂功能划分成若干模块,让程序结构更加清晰,代码重复利用率更高.像其他编程语言一样,Shell 也支持函数.Shell 函数必须先定义后使用. 函数定义 Shell 函数的定义格式 ...

  4. PHP变量作用域

    PHP 的全局变量和 C 语言有一点点不同,在 C 语言中,全局变量在函数中自动生效,除非被局部变量覆盖,这可能引起一些问题,有些人可能不小心就改变了一个全局变量.PHP 中全局变量在函数中使用时必须 ...

  5. [Java面试十]浏览器跨域问题.

    此块内容参考Ajax文档部分. 主要复习内容:     1.JavaScript核心对象     2.浏览器BOM对象     3.文档对象模型DOM     4.常见事件     5.Ajax编程( ...

  6. SQLServer数据库还原提示 数据库正在使用,无法获得独占访问权

    还原数据库的时候提示下图的错误:

  7. React(三)组件的生命周期

    Component Specs and LifeCycle <div id="app"></div> <script src="bower_ ...

  8. JavaScript 模板引擎实现原理解析

    1.入门实例 首先我们来看一个简单模板: <script type="template" id="template"> <h2> < ...

  9. Python之函数与变量

    本节内容 函数介绍及其作用 函数的定义与调用 函数的参数说明 全局变量与局部变量 值传递和引用传递 一.函数的介绍及其作用 编程语言中的函数与数学中的函数是有区别的:数学中的函数有参数(输入),就会有 ...

  10. c#将list集合转换为datatable的简单办法

    public static class ExtensionMethods        {        /// <summary>        /// 将List转换成DataTabl ...