前面介绍了六种.NET组件,其中有一种组件是写文件的压缩和解压,现在介绍另一种文件的解压缩组件SharpZipLib。在这个组件介绍系列中,只为简单的介绍组件的背景和简单的应用,读者在阅读时可以结合官网的相关介绍和在本地实际操作。

相关的组件功能非常强大,在笔者的介绍中只是提及到简单的应用,需要了解更多的操作和特性,可以根据官网介绍,或者查看DLL文件的相关类和方法,以此来扩展相关的业务需要。

SharpZipLib是一个完全在C#中为.NET平台编写的Zip,GZip,Tar和BZip2库。

一.SharpZipLib组件概述:

ziplib(SharpZipLib,以前的NZipLib)是一个完全在C#为.NET平台编写的Zip,GZip,Tar和BZip2库。它实现为一个程序集(可安装在GAC中),因此可以轻松地集成到其他项目(任何.NET语言)中。 #ziplib的创建者这样说:“我已经将zip库移植到C#,因为我需要gzip / zip压缩,我不想使用libzip.dll或类似的东西我想要的所有在纯C#“。

SharpZipLib官网提供的下载操作:.NET 1.1,.NET 2.0(3.5,4.0),.NET CF 1.0,.NET CF 2.0的装配:下载237 KB,源代码和示例下载708 KB;源代码和示例下载708 KB;帮助文件下载1208 KB;

SharpZipLib是在GPL下发布,遵守开源协议。

二.SharpZipLib核心类和方法介绍:

以上简单的介绍了SharpZipLib组件的相关背景,现在具体看一下该组件的相关核心类和方法:

1.ZipOutputStream类PutNextEntry():

public void PutNextEntry(ZipEntry entry)
{
bool hasCrc;
if (entry == null)
{
throw new ArgumentNullException("entry");
}
if (this.entries == null)
{
throw new InvalidOperationException("ZipOutputStream was finished");
}
if (this.curEntry != null)
{
this.CloseEntry();
}
if (this.entries.Count == 0x7fffffff)
{
throw new ZipException("Too many entries for Zip file");
}
CompressionMethod compressionMethod = entry.CompressionMethod;
int defaultCompressionLevel = this.defaultCompressionLevel;
entry.Flags &= 0x800;
this.patchEntryHeader = false;
if (entry.Size == 0L)
{
entry.CompressedSize = entry.Size;
entry.Crc = 0L;
compressionMethod = CompressionMethod.Stored;
hasCrc = true;
}
else
{
hasCrc = (entry.Size >= 0L) && entry.HasCrc;
if (compressionMethod == CompressionMethod.Stored)
{
if (!hasCrc)
{
if (!base.CanPatchEntries)
{
compressionMethod = CompressionMethod.Deflated;
defaultCompressionLevel = ;
}
}
else
{
entry.CompressedSize = entry.Size;
hasCrc = entry.HasCrc;
}
}
}
if (!hasCrc)
{
if (!base.CanPatchEntries)
{
entry.Flags |= ;
}
else
{
this.patchEntryHeader = true;
}
}
if (base.Password != null)
{
entry.IsCrypted = true;
if (entry.Crc < 0L)
{
entry.Flags |= ;
}
}
entry.Offset = this.offset;
entry.CompressionMethod = compressionMethod;
this.curMethod = compressionMethod;
this.sizePatchPos = -1L;
if ((this.useZip64_ == UseZip64.On) || ((entry.Size < 0L) && (this.useZip64_ == UseZip64.Dynamic)))
{
entry.ForceZip64();
}
this.WriteLeInt(0x4034b50);
this.WriteLeShort(entry.Version);
this.WriteLeShort(entry.Flags);
this.WriteLeShort((byte) entry.CompressionMethodForHeader);
this.WriteLeInt((int) entry.DosTime);
if (hasCrc)
{
this.WriteLeInt((int) entry.Crc);
if (entry.LocalHeaderRequiresZip64)
{
this.WriteLeInt(-);
this.WriteLeInt(-);
}
else
{
this.WriteLeInt(entry.IsCrypted ? (((int) entry.CompressedSize) + ) : ((int) entry.CompressedSize));
this.WriteLeInt((int) entry.Size);
}
}
else
{
if (this.patchEntryHeader)
{
this.crcPatchPos = base.baseOutputStream_.Position;
}
this.WriteLeInt();
if (this.patchEntryHeader)
{
this.sizePatchPos = base.baseOutputStream_.Position;
}
if (entry.LocalHeaderRequiresZip64 || this.patchEntryHeader)
{
this.WriteLeInt(-);
this.WriteLeInt(-);
}
else
{
this.WriteLeInt();
this.WriteLeInt();
}
}
byte[] buffer = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
if (buffer.Length > 0xffff)
{
throw new ZipException("Entry name too long.");
}
ZipExtraData extraData = new ZipExtraData(entry.ExtraData);
if (entry.LocalHeaderRequiresZip64)
{
extraData.StartNewEntry();
if (hasCrc)
{
extraData.AddLeLong(entry.Size);
extraData.AddLeLong(entry.CompressedSize);
}
else
{
extraData.AddLeLong(-1L);
extraData.AddLeLong(-1L);
}
extraData.AddNewEntry();
if (!extraData.Find())
{
throw new ZipException("Internal error cant find extra data");
}
if (this.patchEntryHeader)
{
this.sizePatchPos = extraData.CurrentReadIndex;
}
}
else
{
extraData.Delete();
}
if (entry.AESKeySize > )
{
AddExtraDataAES(entry, extraData);
}
byte[] entryData = extraData.GetEntryData();
this.WriteLeShort(buffer.Length);
this.WriteLeShort(entryData.Length);
if (buffer.Length > )
{
base.baseOutputStream_.Write(buffer, , buffer.Length);
}
if (entry.LocalHeaderRequiresZip64 && this.patchEntryHeader)
{
this.sizePatchPos += base.baseOutputStream_.Position;
}
if (entryData.Length > )
{
base.baseOutputStream_.Write(entryData, , entryData.Length);
}
this.offset += ( + buffer.Length) + entryData.Length;
if (entry.AESKeySize > )
{
this.offset += entry.AESOverheadSize;
}
this.curEntry = entry;
this.crc.Reset();
if (compressionMethod == CompressionMethod.Deflated)
{
base.deflater_.Reset();
base.deflater_.SetLevel(defaultCompressionLevel);
}
this.size = 0L;
if (entry.IsCrypted)
{
if (entry.AESKeySize > )
{
this.WriteAESHeader(entry);
}
else if (entry.Crc < 0L)
{
this.WriteEncryptionHeader(entry.DosTime << 0x10);
}
else
{
this.WriteEncryptionHeader(entry.Crc);
}
}
}

2.ZipOutputStream类Finish():

public override void Finish()
{
if (this.entries != null)
{
if (this.curEntry != null)
{
this.CloseEntry();
}
long count = this.entries.Count;
long sizeEntries = 0L;
foreach (ZipEntry entry in this.entries)
{
this.WriteLeInt(0x2014b50);
this.WriteLeShort(0x33);
this.WriteLeShort(entry.Version);
this.WriteLeShort(entry.Flags);
this.WriteLeShort((short) entry.CompressionMethodForHeader);
this.WriteLeInt((int) entry.DosTime);
this.WriteLeInt((int) entry.Crc);
if (entry.IsZip64Forced() || (entry.CompressedSize >= 0xffffffffL))
{
this.WriteLeInt(-);
}
else
{
this.WriteLeInt((int) entry.CompressedSize);
}
if (entry.IsZip64Forced() || (entry.Size >= 0xffffffffL))
{
this.WriteLeInt(-);
}
else
{
this.WriteLeInt((int) entry.Size);
}
byte[] buffer = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
if (buffer.Length > 0xffff)
{
throw new ZipException("Name too long.");
}
ZipExtraData extraData = new ZipExtraData(entry.ExtraData);
if (entry.CentralHeaderRequiresZip64)
{
extraData.StartNewEntry();
if (entry.IsZip64Forced() || (entry.Size >= 0xffffffffL))
{
extraData.AddLeLong(entry.Size);
}
if (entry.IsZip64Forced() || (entry.CompressedSize >= 0xffffffffL))
{
extraData.AddLeLong(entry.CompressedSize);
}
if (entry.Offset >= 0xffffffffL)
{
extraData.AddLeLong(entry.Offset);
}
extraData.AddNewEntry();
}
else
{
extraData.Delete();
}
if (entry.AESKeySize > )
{
AddExtraDataAES(entry, extraData);
}
byte[] entryData = extraData.GetEntryData();
byte[] buffer3 = (entry.Comment != null) ? ZipConstants.ConvertToArray(entry.Flags, entry.Comment) : new byte[];
if (buffer3.Length > 0xffff)
{
throw new ZipException("Comment too long.");
}
this.WriteLeShort(buffer.Length);
this.WriteLeShort(entryData.Length);
this.WriteLeShort(buffer3.Length);
this.WriteLeShort();
this.WriteLeShort();
if (entry.ExternalFileAttributes != -)
{
this.WriteLeInt(entry.ExternalFileAttributes);
}
else if (entry.IsDirectory)
{
this.WriteLeInt(0x10);
}
else
{
this.WriteLeInt();
}
if (entry.Offset >= 0xffffffffL)
{
this.WriteLeInt(-);
}
else
{
this.WriteLeInt((int) entry.Offset);
}
if (buffer.Length > )
{
base.baseOutputStream_.Write(buffer, , buffer.Length);
}
if (entryData.Length > )
{
base.baseOutputStream_.Write(entryData, , entryData.Length);
}
if (buffer3.Length > )
{
base.baseOutputStream_.Write(buffer3, , buffer3.Length);
}
sizeEntries += ((0x2e + buffer.Length) + entryData.Length) + buffer3.Length;
}
using (ZipHelperStream stream = new ZipHelperStream(base.baseOutputStream_))
{
stream.WriteEndOfCentralDirectory(count, sizeEntries, this.offset, this.zipComment);
}
this.entries = null;
}
}

3.ZipEntry类Clone():

public object Clone()
{
ZipEntry entry = (ZipEntry) base.MemberwiseClone();
if (this.extra != null)
{
entry.extra = new byte[this.extra.Length];
Array.Copy(this.extra, , entry.extra, , this.extra.Length);
}
return entry;
}

   4.ZipOutputStream类Write():

public override void Write(byte[] buffer, int offset, int count)
{
if (this.curEntry == null)
{
throw new InvalidOperationException("No open entry.");
}
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
if (offset < )
{
throw new ArgumentOutOfRangeException("offset", "Cannot be negative");
}
if (count < )
{
throw new ArgumentOutOfRangeException("count", "Cannot be negative");
}
if ((buffer.Length - offset) < count)
{
throw new ArgumentException("Invalid offset/count combination");
}
this.crc.Update(buffer, offset, count);
this.size += count;
switch (this.curMethod)
{
case CompressionMethod.Stored:
if (base.Password != null)
{
this.CopyAndEncrypt(buffer, offset, count);
}
else
{
base.baseOutputStream_.Write(buffer, offset, count);
}
break; case CompressionMethod.Deflated:
base.Write(buffer, offset, count);
break;
}
}

三.SharpZipLib实例:

1.压缩单个文件:

        /// <summary>
/// 压缩单个文件
/// </summary>
/// <param name="fileToZip">要压缩的文件</param>
/// <param name="zipedFile">压缩后的文件</param>
/// <param name="compressionLevel">压缩等级</param>
/// <param name="blockSize">每次写入大小</param>
public static void ZipFile(string fileToZip, string zipedFile, int compressionLevel, int blockSize)
{
if (string.IsNullOrEmpty(fileToZip))
{
throw new ArgumentNullException(fileToZip);
}
if (string.IsNullOrEmpty(zipedFile))
{
throw new ArgumentNullException(zipedFile);
}
if (!File.Exists(fileToZip))
{
throw new FileNotFoundException("指定要压缩的文件: " + fileToZip + " 不存在!");
}
try
{
using (var zipFile = File.Create(zipedFile))
{
using (var zipStream = new ZipOutputStream(zipFile))
{
using (var streamToZip = new FileStream(fileToZip, FileMode.Open, FileAccess.Read))
{
var fileName = fileToZip.Substring(fileToZip.LastIndexOf("\\", StringComparison.Ordinal) + );
var zipEntry = new ZipEntry(fileName);
zipStream.PutNextEntry(zipEntry);
zipStream.SetLevel(compressionLevel);
var buffer = new byte[blockSize];
try
{
int sizeRead;
do
{
sizeRead = streamToZip.Read(buffer, , buffer.Length);
zipStream.Write(buffer, , sizeRead);
}
while (sizeRead > );
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
streamToZip.Close();
}
zipStream.Finish();
zipStream.Close();
}
zipFile.Close();
}
}
catch (IOException ioex)
{
throw new IOException(ioex.Message);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
} }

2. 压缩单个文件:

       /// <summary>
/// 压缩单个文件
/// </summary>
/// <param name="fileToZip">要进行压缩的文件名</param>
/// <param name="zipedFile">压缩后生成的压缩文件名</param>
public static void ZipFile(string fileToZip, string zipedFile)
{
if (string.IsNullOrEmpty(fileToZip))
{
throw new ArgumentException(fileToZip);
}
if (string.IsNullOrEmpty(zipedFile))
{
throw new ArgumentException(zipedFile);
}
if (!File.Exists(fileToZip))
{
throw new FileNotFoundException("指定要压缩的文件: " + fileToZip + " 不存在!");
}
try
{
using (var fs = File.OpenRead(fileToZip))
{
var buffer = new byte[fs.Length];
fs.Read(buffer, , buffer.Length);
fs.Close();
using (var zipFile = File.Create(zipedFile))
{
using (var zipStream = new ZipOutputStream(zipFile))
{
var fileName = fileToZip.Substring(fileToZip.LastIndexOf("\\", StringComparison.Ordinal) + );
var zipEntry = new ZipEntry(fileName);
zipStream.PutNextEntry(zipEntry);
zipStream.SetLevel();
zipStream.Write(buffer, , buffer.Length);
zipStream.Finish();
zipStream.Close();
}
}
}
}
catch (IOException ioex)
{
throw new IOException(ioex.Message);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
} }

3.压缩多层目录:

        /// <summary>
/// 压缩多层目录
/// </summary>
/// <param name="strDirectory">目录</param>
/// <param name="zipedFile">压缩文件</param>
public static void ZipFileDirectory(string strDirectory, string zipedFile)
{
if (string.IsNullOrEmpty(strDirectory))
{
throw new ArgumentException(strDirectory);
}
if (string.IsNullOrEmpty(zipedFile))
{
throw new ArgumentException(zipedFile);
}
using (var zipFile = File.Create(zipedFile))
{
using (var s = new ZipOutputStream(zipFile))
{
ZipSetp(strDirectory, s, "");
}
}
}

4.递归遍历目录:

       /// <summary>
/// 递归遍历目录
/// </summary>
/// <param name="strDirectory">目录</param>
/// <param name="s">ZipOutputStream对象</param>
/// <param name="parentPath">父路径</param>
private static void ZipSetp(string strDirectory, ZipOutputStream s, string parentPath)
{
if (strDirectory[strDirectory.Length - ] != Path.DirectorySeparatorChar)
{
strDirectory += Path.DirectorySeparatorChar;
}
var crc = new Crc32(); var filenames = Directory.GetFileSystemEntries(strDirectory);
try
{
// 遍历所有的文件和目录
foreach (var file in filenames)
{
// 先当作目录处理如果存在这个目录就递归Copy该目录下面的文件
if (Directory.Exists(file))
{
var pPath = parentPath;
pPath += file.Substring(file.LastIndexOf("\\", StringComparison.Ordinal) + );
pPath += "\\";
ZipSetp(file, s, pPath);
}
// 否则直接压缩文件
else
{
//打开压缩文件
using (var fs = File.OpenRead(file))
{
var buffer = new byte[fs.Length];
fs.Read(buffer, , buffer.Length);
var fileName = parentPath + file.Substring(file.LastIndexOf("\\", StringComparison.Ordinal) + );
var entry = new ZipEntry(fileName)
{
DateTime = DateTime.Now,
Size = fs.Length
};
fs.Close();
crc.Reset();
crc.Update(buffer);
entry.Crc = crc.Value;
s.PutNextEntry(entry);
s.Write(buffer, , buffer.Length);
}
}
}
}
catch (IOException ioex)
{
throw new IOException(ioex.Message);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
} }

5.解压缩一个 zip 文件:

       /// <summary>
/// 解压缩一个 zip 文件。
/// </summary>
/// <param name="zipedFile">The ziped file.</param>
/// <param name="strDirectory">The STR directory.</param>
/// <param name="password">zip 文件的密码。</param>
/// <param name="overWrite">是否覆盖已存在的文件。</param>
public void UnZip(string zipedFile, string strDirectory, string password, bool overWrite)
{
if (string.IsNullOrEmpty(zipedFile))
{
throw new ArgumentException(zipedFile);
}
if (string.IsNullOrEmpty(strDirectory))
{
throw new ArgumentException(strDirectory);
}
if (string.IsNullOrEmpty(password))
{
throw new ArgumentException(password);
}
if (strDirectory == "")
{
strDirectory = Directory.GetCurrentDirectory();
}
if (!strDirectory.EndsWith("\\"))
{
strDirectory = strDirectory + "\\";
}
try
{
using (var s = new ZipInputStream(File.OpenRead(zipedFile)))
{
s.Password = password;
ZipEntry theEntry;
while ((theEntry = s.GetNextEntry()) != null)
{
var directoryName = string.Empty;
var pathToZip = theEntry.Name;
if (pathToZip != "")
{
directoryName = Path.GetDirectoryName(pathToZip) + "\\";
}
var fileName = Path.GetFileName(pathToZip);
Directory.CreateDirectory(strDirectory + directoryName);
if (fileName == "") continue;
if ((!File.Exists(strDirectory + directoryName + fileName) || !overWrite) &&
(File.Exists(strDirectory + directoryName + fileName))) continue;
using (var streamWriter = File.Create(strDirectory + directoryName + fileName))
{
var data = new byte[];
while (true)
{
var size = s.Read(data, , data.Length); if (size > )
streamWriter.Write(data, , size);
else
break;
}
streamWriter.Close();
}
} s.Close();
}
}
catch (IOException ioex)
{
throw new IOException(ioex.Message);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
} }

四.总结:

以上是对SharpZipLib组件的相关介绍,本文的讲解上比较的浅显,如果需要深入的学习可以进入官网进行详细的学习。组件的功能是很强大的,如何在项目中使用组件,完成我们在项目中需要实现的功能,这就是对每个开发者提出了要求,需要我们仔细的去考虑。

任何学习都需要我们自己去探索和思考,对于一个开发者来说,最重要的就是思考,因为在我们的职业生涯中,没有什么的重要性能够超过思考。如果有不足之处还望各位读者包含,并留言指正。

.NET组件介绍系列:

一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)http://www.cnblogs.com/pengze0902/p/6122311.html

高效而稳定的企业级.NET Office 组件Spire(.NET组件介绍之二)http://www.cnblogs.com/pengze0902/p/6125570.html

最好的.NET开源免费ZIP库DotNetZip(.NET组件介绍之三)http://www.cnblogs.com/pengze0902/p/6124659.html

免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)http://www.cnblogs.com/pengze0902/p/6134506.html

免费开源的DotNet任务调度组件Quartz.NET(.NET组件介绍之五)http://www.cnblogs.com/pengze0902/p/6128558.html

免费高效实用的Excel操作组件NPOI(.NET组件介绍之六)http://www.cnblogs.com/pengze0902/p/6150070.html

免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)http://www.cnblogs.com/pengze0902/p/6159497.html

免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)的更多相关文章

  1. Tippy.js - 免费开源且高度可定制的气泡提示独立组件

    推荐一个非常优秀的 web 气泡提示独立UI组件. 介绍 Tippy.js 是一款用于Web的完整工具提示,弹出菜单,下拉菜单和菜单解决方案.适用于鼠标,键盘和触摸输入. 特点 超轻量的纯 javas ...

  2. 免费开源的DotNet任务调度组件Quartz.NET(.NET组件介绍之五)

    很多的软件项目中都会使用到定时任务.定时轮询数据库同步,定时邮件通知等功能..NET Framework具有“内置”定时器功能,通过System.Timers.Timer类.在使用Timer类需要面对 ...

  3. 免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)

    在生活中有一种东西几乎已经快要成为我们的另一个电子”身份证“,那就是二维码.无论是在软件开发的过程中,还是在普通用户的日常中,几乎都离不开二维码.二维码 (dimensional barcode) , ...

  4. 开源的.NET媒体文件操作组件TagLib#解析

    人生得意须尽欢 莫使金樽空对月.写博客都会在吃饭后,每次吃饭都要喝上二两小酒,写博客前都要闲扯,这些都是个人爱好,改不掉了,看不惯的人,还望多多包含一下,有相同爱好的同学,咱们可以一起喝着小酒一边吹牛 ...

  5. 简单易用的.NET免费开源RabbitMQ操作组件EasyNetQ解析

    对于目前大多的.NET项目,其实使用的技术栈都是差不多,估计现在很少用控件开发项目的了,毕竟一大堆问题.对.NET的项目,目前比较适合的架构ASP.NET MVC,ASP.NET WebAPI,ORM ...

  6. 「免费开源」基于Vue和Quasar的前端SPA项目crudapi后台管理系统实战之自定义组件(四)

    基于Vue和Quasar的前端SPA项目实战之序列号(四) 回顾 通过上一篇文章 基于Vue和Quasar的前端SPA项目实战之布局菜单(三)的介绍,我们已经完成了布局菜单,本文主要介绍序列号功能的实 ...

  7. .NET平台开源项目速览(8)Expression Evaluator表达式计算组件使用

    在文章:这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧!(第二辑)中,给大家初步介绍了一下Expression Evaluator验证组件.那里只是概述了一下,并没有对其使用和强大功能做 ...

  8. Scut游戏服务器免费开源框架-3

    Scut游戏服务器免费开源框架--快速开发(3) Scut快速开发(3) 1        开发环境 需要安装的软件 a)        消息队列 b)        数据库,Sql2005以上版本 ...

  9. 全球第一免费开源ERP Odoo工业互联网生产制造功能模块术语解析

    物料清单 物料清单(BoM)用于描述物料.每种物料的数量.以及制造某一产品所需的步骤.由于行业和成品性质的不同,同一个文件可能有不同的命名.例如,在制药行业中,可以使用术语“处方”. 周期 产品周期是 ...

随机推荐

  1. Linux下服务器端开发流程及相关工具介绍(C++)

    去年刚毕业来公司后,做为新人,发现很多东西都没有文档,各种工具和地址都是口口相传的,而且很多时候都是不知道有哪些工具可以使用,所以当时就想把自己接触到的这些东西记录下来,为后来者提供参考,相当于一个路 ...

  2. 窥探Vue.js 2.0 - Virtual DOM到底是个什么鬼?

    引言 你可能听说在Vue.js 2.0已经发布,并且在其中新添加如了一些新功能.其中一个功能就是"Virtual DOM". Virtual DOM是什么 在之前,React和Em ...

  3. InnoDB关键特性学习笔记

    插入缓存 Insert Buffer Insert Buffer是InnoDB存储引擎关键特性中最令人激动与兴奋的一个功能.不过这个名字可能会让人认为插入缓冲是缓冲池中的一个组成部分.其实不然,Inn ...

  4. iOS开发之Masonry框架源码深度解析

    Masonry是iOS在控件布局中经常使用的一个轻量级框架,Masonry让NSLayoutConstraint使用起来更为简洁.Masonry简化了NSLayoutConstraint的使用方式,让 ...

  5. Shell碎碎念

    1. 字符串如何大小写转换 str="This is a Bash Shell script." 1> tr方式 newstr=`tr '[A-Z]' '[a-z]' < ...

  6. AFNetworking 3.0 源码解读(九)之 AFNetworkActivityIndicatorManager

    让我们的APP像艺术品一样优雅,开发工程师更像是一名匠人,不仅需要精湛的技艺,而且要有一颗匠心. 前言 AFNetworkActivityIndicatorManager 是对状态栏中网络激活那个小控 ...

  7. PhpStorm和WAMP配置调试参数,问题描述Error. Interpreter is not specified or invalid. Press “Fix” to edit your project configuration.

    PhpStorm和WAMP配置调试参数 问题描述: Error. Interpreter is not specified or invalid. Press “Fix” to edit your p ...

  8. BPM应用开发解决方案分享

    一.需求分析企业整体管理是一个完整的体系,如果 把这个体系比做一个拼图,企业信息化通过各个业务系统覆盖了一部分业务. 企业通过采购实施通用软件的方式,覆盖了企业的核心业务和专业化业务然而系统只满足了部 ...

  9. Android之SAX解析XML

    一.SAX解析方法介绍 SAX(Simple API for XML)是一个解析速度快并且占用内存少的XML解析器,非常适合用于Android等移动设备. SAX解析器是一种基于事件的解析器,事件驱动 ...

  10. 编写一个通用的Makefile文件

    1.1在这之前,我们需要了解程序的编译过程 a.预处理:检查语法错误,展开宏,包含头文件等 b.编译:*.c-->*.S c.汇编:*.S-->*.o d.链接:.o +库文件=*.exe ...