2023年12月30日发(作者:)

述:

在这篇文件中,讲述对单个文件的数据加密、数据压缩、自解压的实现。同样,也可以实现对多个文件或文件夹的压缩,只要稍加修改便可实现。

关键字:加密压缩、Zlib、流、资源文件

引言:

在日常中,我们一定使用过WINZIP、WINRAR这样的出名的压缩软件,就是我们开发软件过程中不免要遇到数据加密、数据压缩的问题!本文中就这一技术问题展开探讨,同时感谢各位网友的技巧,在我每次面对问题要解决的时候,是你们辛苦地摸索出来的技巧总是让我豁然开朗,问题迎刃而解。本篇文章主要是运用DELPH的强大的流处理方面的技巧来实现的数据加密压缩,并用于实际的软件程序开发中,将我个人的心得、开发经验写出来与大家分享。

1、系统功能

1、数据压缩

使用DELPHI提供的两个流类

2、数据加密压缩

通过Delphi编程中"流"的应用实现数据加密,主要采用Tstream的两个派生类Tfilestream、Tmemorystream 来完成的;其中数据压缩部分采用1的实现方法

3、双击压缩文件自动关联解压

通过更改注册表的实现扩展名与程序文件的关联,主要采用Tregistry;并且,API函数SHChangeNotify实现注册效果的立即呈现。

4、可生成自解压文件

1 / 30

自解压的文件实现数据压缩1与数据加密压缩2的自动解压;并且,通过资源文件的使用实现可执行的自解压文件与数据文件的合并,来完成数据的自解压实现。

2、系统实现

2.1、工作原理

2.2、关键技术的讲述

<一ZLIB

1、基类 TCustomZlibStream:是类TCompressionStream和TDecompressionStream 类的基类,它主要有一个属性: OnProgress,在类进行压缩或解压缩的过程中会发生这个的事件。

格式:Procedure OnProgress

2、压缩类TCompressionStream:除了继承了基类的OnProgress 属性外,又增加了一个属性:CompressionRate,它的定义如下:

Property CompressionRate: Single read GetCompressionRate;

通过这个属性,可以得到压缩比。

它的几个重要的方法定义如下:

Constructor

TCompressionLevel; Dest: TStrea m;

其中:TcompressionLevel<压缩类型,它由如下几个定义:

1、 clNone :不进行数据压缩;

2、 clFastest:进行快速压缩,牺牲压缩效率;

2 / 30

3、 clDefault:进行正常压缩;

4、 clMax:进行最大化压缩,牺牲速度;

Dest:目的流,用于存放压缩过的数据。

Function

Longint;

其中:Buffer:需要压缩的数据;

Count: 需要压缩的数据的字节数;

函数返回写入流的字节数。

注意:压缩类TCompressionStream的数据只能是写入的,如果试图从其内部读取数据,将发生一个"Error "异常。需要压缩的数据通过方法 Write写入流中,在写入的过程中就被压缩,并保存在由构造函数提供的内存流

3、解压缩类 TDecompressionStream :和压缩类TcompressionStream相反,它的数据是只能读出的,如果试图往其内部写数据,将发生一个"Error "异常。

它的几个重要方法定义如下:

构造函数:Constructor Create

其中:Source 是保存着压缩数据的流;

Function Read

数据读出函数,Buffer:存数据缓冲区;Count: 缓冲区的大小;

函数返回读出的字节数。数据在读出的过程中,数据被解压缩,并触发

OnProcess 事件。

3 / 30

<二流

在Delphi中,所有流对象的基类为TStream类,其中定义了所有流的共同属性和方法。TStream类中定义的属性如下:

1、Size:此属性以字节返回流中数据大小。

2、Position:此属性控制流中存取指针的位置。

Tstream中定义的虚方法有四个:

1、Read:此方法实现将数据从流中读出,返回值为实际读出的字节数,它可以小于或等于指定的值。

2、Write:此方法实现将数据写入流中,返回值为实际写入流中的字节数。

3、Seek:此方法实现流中读取指针的移动,返回值为移动后指针的位置。

函数原形为:Function

Seek

参数Offset为偏移字节数,参数Origint指出Offset的实际意义,其可能的取值如下: soFromBeginning:Offset为指针距离数据开始的位置。此时Offset必须大于或者等于零。soFromCurrent:Offset为移动后指针与当前指针的相对位置。

soFromEnd:Offset为移动后指针距离数据结束的位置。此时Offset必须小于或者等于零。

4、Setsize:此方法实现改变数据的大小。

另外,TStream类中还定义了几个静态方法:

1、ReadBuffer:此方法的作用是从流中当前位置读取数据,跟上面的Read相同。

4 / 30

注意:当读取的数据字节数与需要读取的字节数不相同时,将产生EReadError异常。2、WriteBuffer:此方法的作用是在当前位置向流写入数据,跟上面的Write相同。

注意:当写入的数据字节数与需要写入的字节数不相同时,将产生EWriteError异常。3、CopyFrom:此方法的作用是从其它流中拷贝数据流。

函数原形为:Function CopyFrom

参数Source为提供数据的流,Count为拷贝的数据字节数。当Count大于0时,CopyFrom 从Source参数的当前位置拷贝Count个字节的数据;当Count等于0时,CopyFrom设置Source参数的Position属性为0,然后拷贝Source的所有数据;

Tstream常见派生类:

TFileStream <文件流的存取

TStringStream <处理内存中的字符串类型数据

TmemoryStream <对于工作的内存区域数据处理

TBlobStream

TwinSocketStream

ToleStream

TresourceStream <资源文件流的处理

其中最常用的是TFileStream类。使用TFileStream类来存取文件,首先要建立一个实例。声明如下:

constructor Create

Filename为文件名<包括路径

5 / 30

Mode为打开文件的方式,它包括文件的打开模式和共享模式,其可能的取值和意义如下:打开模式:

fmCreate :用指定的文件名建立文件,如果文件已经存在则打开它。

fmOpenRead :以只读方式打开指定文件

fmOpenWrite :以只写方式打开指定文件

fmOpenReadWrite:以写写方式打开指定文件

共享模式:

fmShareCompat :共享模式与FCBs兼容

fmShareExclusive:不允许别的程序以任何方式打开该文件

fmShareDenyWrite:不允许别的程序以写方式打开该文件

fmShareDenyRead :不允许别的程序以读方式打开该文件

fmShareDenyNone :别的程序可以以任何方式打开该文件

<三资源文件

1、创建资源文件

首先创建一个.Rc的纯文本文件。

格式:资源标识符关键字资源文件名

资源标识符:程序中调用资源时的特殊标号;

关键字:标识资源文件类型;

Wave:资源文件是声音文件;

6 / 30

RCDATA: JPEG文件;

A VI: A VI动画;

ICON:图标文件;

BITMAP:位图文件;

CURSOR:光标文件;

EXEFILE : EXE文件

资源文件名:资源文件的在磁盘上存储的文件全名

例如:

myzjy exefile

2、编译资源文件

在DELPHI的安装目录的Bin下,使用编译资源文件.RC。当然,也可以将BRCC32单独拷贝到程序文档目录使用。

例如:

Brcc32 wnhoo_

3、资源文件引用

implementation

{$R *.dfm}

{$R wnhoo_}

7 / 30

4、调用资源文件

<1存取资源文件中的位图

:=LoadBitmap

注:如果位图没有装载成功,程序仍旧执行,但是Image将不再显示图片。你可以根据LoadBitmap函数的返回值判断是否装载成功,如果装载成功返回值是非0,如果装载失败返回值是0。

另外一个存取显示位图的方法如下

eName

<2存取资源文件中的光标

s[]是一个光标数组,使用光标文件我们可以将定制的光标加入到这个属性中。

因为默认的光标在数组中索引值是0,所以除非想取代默认光标,最好将定制的光标索引值设为1。

s[1] :=LoadCursor

:=1;

<3存取资源文件中的图标

将图标放在资源文件中,可以实现动态改变应用程序图标。

:= LoadIcon

<4存取资源文件中的A VI

8 / 30

e :='MyAvi' ; //资源标识符号

:=True ;

<5存取资源文件中的JPEG

把jpeg单元加入到uses单元中。

var

Fjpg : TJpegImage ;

FStream :TResourceStream ;

begin

Fjpg := ;

//TresourceStream使用

FStream :=

omStream

<6存取资源文件中的Wave

把MMSystem加入uses单元中

PlaySound

snd_Resource ;

<四INI文件操作

<1 INI文件的结构:

9 / 30

;这是关于INI文件的注释部分

[节点]

关键字=值

...

INI文件允许有多个节点,每个节点又允许有多个关键字,"="后面是该关键字的值<类型有三种:字符串、整型数值和布尔值。其中字符串存贮在INI文件中时没有引号,布尔真值用1表示,布尔假值用0表示。注释以分号";"开头。

<2 INI文件的操作

1、在Interface的Uses节增加IniFiles;

2、在Var变量定义部分增加一行:inifile:Tinifile;然后,就可以对变量myinifile进行创建、打开、读取、写入等操作了。

3、打开INI文件:inifile:=<'';

4、读取关键字的值:

a:=ring<'节点','关键字',缺省值;// string类型

b:=teger<'节点','关键字',缺省值;// integer类型

c:=ol<'节点','关键字',缺省值;// boolean类型

其中[缺省值]为该INI文件不存在该关键字时返回的缺省值。

5、写入INI文件:

tring<'节点','关键字',变量或字符串值;

nteger<'节点','关键字',变量或整型值;

10 / 30

ool<'节点','关键字',变量或True或False;

当这个INI文件的节点不存在时,上面的语句还会自动创建该INI文件。

6、删除关键字:

Key<'节点','关键字';//关键字删除

ection<'节点';// 节点删除

7、节点操作:

ction<'节点',TStrings变量;//可将指定小节中的所有关键字名读取至一个字符串列表变量中;

ctions

ctionvalues<'节点',TStrings变量;//可将INI文件中指定小节的所有行<包括关键字、=、值读取至一个字符串列表变量中去。

8、释放:y;或;

<五文件关联

uses

registry, shlobj;

//实现关联注册

procedure ;

var

reg: TRegistry;

11 / 30

begin

reg := ;

y := HKEY_CLASSES_ROOT;

y<'.zzz', true;

tring<'', 'myzip';

ey;

y<'myzipshellopencommand', true;

//用于打开.zzz文件的可执行程序

tring<'', '"' + e + '" "%1"';

ey;

y<'myzipDefaultIcon',true;

//取当前可执行程序的图标为.zzz文件的图标

tring<'',''+e+',0';

;

//立即刷新

SHChangeNotify

end;

2.3、加密压缩的实现

1、生成INI临时加密文件

12 / 30

用于加密的INI的临时文件格式:

[FILE1]//节点,在软件中使用FILE1..N可以实现多文件加密

FILENAME=压缩文件名

PASSWORD=解压密码

FILESIZE=文件大小

FILEDATE=创建日期

ISJM=解压是否需要密码

如果是实现多文件、文件夹的信息存储,可以将密码关键字存在一个总的节点下。本文中仅是实现对单个文件的加密,所以只要上述格式就可以了。

2、将数据文件与用于加密的INI文件的合并,这可以采用文件流的形式实现。

加密后文件结构图:

图<1

图<2

上面两种形式,可以根据实际采用。本文采用图<1的结构。

3、对于加密后的数据,采用ZLIB技术实现压缩存储,生成新压缩形式的文件。

2.4、文件关联的实现见2.2 <五

2.5、自解压的实现

1.建立一个专门用来自解压的可执行程序文件

2.将1中建立的文件,生成资源文件

13 / 30

3.将资源文件放到本文中这个压缩工具的程序中一起编译。

4.通过将资源文件与压缩文件的合并,生成自解压文件。

自解压文件结构图:

5.自解压实现:通过将自身文件中的加密压缩数据的分解,然后对分解的加密压缩数据再一次解压并分解出真正的数据文件。

2.6 系统程序设计

这是关于这个软件实现的核心部分全部代码,在这里详细讲述这个软件所有的技术细节。// wnhoo_

unit wnhoo_zzz;

interface

uses

Windows,Forms,SysUtils,Classes,zlib,Registry,INIFILES, Dialogs,

shlobj;

type

pass=string[20];

type

Tmyzip = class

private

{ private declarations here}

protected

14 / 30

{ protected declarations here }

public

procedure regzzz;

procedure ys_file

string;password:pass;isjm:boolean;ysbz:integer;

function jy_file

procedure zjywj

constructor Create;

destructor Destroy; override;

{ public declarations here }

published

{ published declarations here }

end;

implementation

constructor ;

begin

inherited Create; // 初始化继承下来的部分

end;

//#####################################################

15 / 30

//原文件加密

procedure jm_File

Target:TMemoryStream;password:pass;isjm:boolean;

{

vfile:加密文件

target:加密后输出目标流》》》

password:密码

isjm:是否加密

-------------------------------------------------------------

加密后文件SIZE=原文件SIZE+[INI加密压缩信息文件]的SIZE+存储[INI加密压缩信息文件]的大小数据类型的SIZE

---------------------------------------------------------------

}

var

tmpstream,inistream:TFileStream;

FileSize:integer;

inifile:TINIFILE;

filename:string;

begin

16 / 30

//打开需要 [加密压缩文件]

tmpstream:=

try

//向 [临时加密压缩文件流] 尾部写入 [原文件流]

<0,soFromEnd;

om

//取得文件路径,生成 [INI加密压缩信息文件]

filename:=ExtractFilePath

inifile:=

tring<'file1','filename',ExtractFileName

tring<'file1','password',password;

nteger<'file1','filesize',;

ateTime<'file1','fileDate',now<;

ool<'file1','isjm',isjm;

;

//读入 [INI加密压缩信息文件流]

inistream:=

fmShareExclusive; try

//继续在 [临时加密压缩文件流] 尾部加入 [INI加密压缩信息文件]

17 / 30

on :=0;

<0,sofromend;

om

//计算当前 [INI加密压缩信息文件] 的大小

FileSize:= ;

//继续在 [临时加密文件尾部] 加入 [INI加密压缩信息文件] 的SIZE信息

uffer

finally

;

deletefile

end;

finally

;

end;

end;

//**************************************************************

//流压缩

procedure ys_stream

{

18 / 30

instream:待压缩的已加密文件流

outStream 压缩后输出文件流

ysbz:压缩标准

}

var

ys: TCompressionStream;

begin

//流指针指向头部

on := 0;

//压缩标准的选择

case ysbz of

1: ys :=

2: ys :=

3: ys :=

4: ys :=

else

ys :=

end;

try

19 / 30

//压缩流

om

finally

;

end;

end;

//*****************************************************************

//流解压

procedure jy_Stream

{

instream :原压缩流文件

outStream:解压后流文件

}

var

jyl: TDeCompressionStream;

buf: array[1..512] of byte;

sjread: integer;

begin

on := 0;

20 / 30

jyl :=

try

repeat

//读入实际大小

sjRead :=

if sjread > 0 then

until

finally

;

end;

end;

//**************************************************************

//实现关联注册

procedure ;

var

reg: TRegistry;

begin

reg := ;

21 / 30

y := HKEY_CLASSES_ROOT;

y<'.zzz', true;

tring<'', 'myzip';

ey;

y<'myzipshellopencommand', true;

//用于打开.zzz文件的可执行程序

tring<'', '"' + e + '" "%1"';

ey;

y<'myzipDefaultIcon',true;

//取当前可执行程序的图标为.zzz文件的图标

tring<'',''+e+',0';

;

//立即刷新

SHChangeNotify

end;

//压缩文件

procedure _file

string;password:pass;isjm:boolean;ysbz:integ

er;

22 / 30

{

}

var

instream:TMemoryStream; //文件加密后的临时流

outStream: TFileStream; //压缩输出文件流

begin

//创建 [文件加密后的临时流]

instream:=;

//文件加密

jm_file

//创建压缩输出文件流

outStream :=

try

//[文件加密后的临时流] 压缩

ys_stream

finally

;

;

end;

23 / 30

end;

//解压文件

function _file

var

inStream,inistream,filestream_ok: TFileStream;

{

f

}

outStream:tmemorystream; //临时内存流

inifile:TINIFILE; //临时INI文件

FileSize:integer; //密码文件的SIZE

resultvalue:boolean;//返回值

begin

try

inStream :=

try

outStream := ;

try

jy_stream

24 / 30

//生成临时INI文件

inistream:=

fmCreate;

try

//指向存储解码信息的INTEGER型变量位置

<-sizeof

//读入变量信息

ffer

//指向解码信息位置

<-

//将解码信息读入INI流中

om

//释放INI文件流

;

//读入INI文件信息

inifile:=

resultvalue:=ol<'file1','isjm',false;

if resultvalue then

begin

25 / 30

if ring <'file1','password',''=trim

resultvalue:=true

else

resultvalue:=false;

end

else

resultvalue:=true;

if resultvalue then

begin

filestream_ok:=

try

on :=0;

filestream_om

finally

filestream_ ;

end;

end;

26 / 30

;

finally

//删除临时INI文件

deletefile

end;

//

finally

;

end;

finally

;

end;

except

resultvalue:=false ;

end;

result:=resultvalue;

end;

//自解压创建

procedure

27 / 30

var

myRes: TResourceStream;//临时存放自解压EXE文件

myfile:tfilestream;//原文件流

xfilename:string;//临时文件名称

file_ok:tmemorystream; //生成文件的内存流

filesize:integer; //原文件大小

begin

if FileExists

begin

//创建内存流

file_ok:= ;

//释放资源文件-- 自解压EXE文件

myRes :=

//将原文件读入内存

myfile:=

try

on:=0;

file_om

file_<0,sofromend;

28 / 30

on:=0;

file_om

file_<0,sofromend;

filesize:=;

file_uffer

file_on:=0;

xfilename:=ChangeFileExt

file_File

finally

;

;

file_ ;

end;

DeleteFile

filename:=xfilename;

end;

end;

//#####################################################

destructor y;

29 / 30

begin

inherited Destroy;

end;

end.

3 、结束语

Delphi的全新可视化编程环境,为我们提供了一种方便、快捷的Windows应用程序开发工具。对于程序开发人员来讲,使用Delphi开发应用软件,无疑会大大地提高编程效率。在delphi中可以很方便的利用流实现文件处理、动态内存处理、网络数据处理等多种数据形式,写起程序也会大大提高效率的。

参考文献:

1、DELPHI系统帮助

2、冯志强. Delphi 中压缩流和解压流的应用

3、陈经韬.谈Delphi编程中"流"

30 / 30