• DELPHI 文件压缩加密 转


    1、  系统功能
    1)、数据压缩 
    使用DELPHI提供的两个流类(TCompressionStream和TDecompressionStream)来完成数据的压缩和解压缩。
    2)、数据加密压缩 
    通过Delphi编程中“流”的应用实现数据加密,主要采用Tstream的两个派生类Tfilestream、Tmemorystream 来完成的;其中数据压缩部分采用1)的实现方法 
    3)、双击压缩文件自动关联解压 
    通过更改注册表的实现扩展名与程序文件的关联,主要采用Tregistry;并且,API函数SHChangeNotify实现注册效果的立即呈现。 
    4)、可生成自解压文件 
    自解压的文件实现数据压缩1)与数据加密压缩2)的自动解压;并且,通过资源文件的使用实现可执行的自解压文件与数据文件的合并,来完成数据的自解压实现。 

    2、  系统实现 
    2.1、工作原理 


    2.2、关键技术的讲述 
    (一)ZLIB 
    1)、基类 TCustomZlibStream:是类TCompressionStream和TDecompressionStream 类的基类,它主要有一个属性: OnProgress,在类进行压缩或解压缩的过程中会发生这个的事件 。 
    格式:Procedure OnProgress (Sender: TObject); dynamic; 
    2)、压缩类TCompressionStream:除了继承了基类的OnProgress 属性外,又增加了一个属性:CompressionRate,它的定义如下: 
    Property CompressionRate: Single read GetCompressionRate; 
    通过这个属性,可以得到压缩比。 
    它的几个重要的方法定义如下: 
    Constructor TCompressionStream.Create (CompressionLevel: TCompressionLevel; Dest: TStream); 
    其中:TcompressionLevel(压缩类型),它由如下几个定义: 
       1)、 clNone :不进行数据压缩; 
       2)、 clFastest:进行快速压缩,牺牲压缩效率; 
       3)、 clDefault:进行正常压缩; 
       4)、 clMax: 进行最大化压缩,牺牲速度; 
    Dest:目的流,用于存放压缩过的数据。 
    Function TCompressionStream.Write (const Buffer; Count: Longint): Longint; 
    其中:Buffer:需要压缩的数据; 
       Count: 需要压缩的数据的字节数; 
    函数返回写入流的字节数。 
    注意:压缩类TCompressionStream的数据只能是写入的,如果试图从其内部读取数据,将发生一个"Error "异常。需要压缩的数据通过方法 Write写入流中,在写入的过程中就被压缩,并保存在由构造函数提供的内存流(TmemoryStream)中,同时触发 OnProcess 事件。 
    3)、 解压缩类 TDecompressionStream :和压缩类TcompressionStream相反,它的数据是只能读出的,如果试图往其内部写数据,将发生一个"Error "异常。 
    它的几个重要方法定义如下: 
    构造函数:Constructor Create(Source: TStream); 
      其中:Source 是保存着压缩数据的流; 
    Function Read(var Buffer; Count: Longint): Longint; 
      数据读出函数,Buffer: 存数据缓冲区;Count: 缓冲区的大小; 
      函数返回读出的字节数。数据在读出的过程中,数据被解压缩,并触发 OnProcess 事件。 


    (二)流 
    在Delphi中,所有流对象的基类为TStream类,其中定义了所有流的共同属性和方法。 
    TStream类中定义的属性如下: 
    1)、Size:此属性以字节返回流中数据大小。 
    2)、Position:此属性控制流中存取指针的位置。 

    Tstream中定义的虚方法有四个: 
    1)、Read:此方法实现将数据从流中读出,返回值为实际读出的字节数,它可以小于或等于指定的值。 
    2)、Write:此方法实现将数据写入流中,返回值为实际写入流中的字节数。 
    3)、Seek:此方法实现流中读取指针的移动,返回值为移动后指针的位置。 
    函数原形为:Function Seek(Offset:Longint;Origint:Word):Longint;virtual;abstract; 
    参数Offset为偏移字节数,参数Origint指出Offset的实际意义,其可能的取值如下: 
    soFromBeginning:Offset为指针距离数据开始的位置。此时Offset必须大于或者等于零。 
    soFromCurrent:Offset为移动后指针与当前指针的相对位置。 
    soFromEnd:Offset为移动后指针距离数据结束的位置。此时Offset必须小于或者等于零。 
    4)、Setsize:此方法实现改变数据的大小。 

    另外,TStream类中还定义了几个静态方法: 
    1)、ReadBuffer:此方法的作用是从流中当前位置读取数据,跟上面的Read相同。 
    注意:当读取的数据字节数与需要读取的字节数不相同时,将产生EReadError异常。 
    2)、WriteBuffer:此方法的作用是在当前位置向流写入数据,跟上面的Write相同。 
    注意:当写入的数据字节数与需要写入的字节数不相同时,将产生EWriteError异常。 
    3)、CopyFrom:此方法的作用是从其它流中拷贝数据流。 
    函数原形为:Function CopyFrom(Source:TStream;Count:Longint):Longint; 
    参数Source为提供数据的流,Count为拷贝的数据字节数。当Count大于0时,CopyFrom从Source参数的当前位置拷贝Count个 字节的数据;当Count等于0时,CopyFrom设置Source参数的Position属性为0,然后拷贝Source的所有数据; 

    Tstream常见派生类: 
    TFileStream       (文件流的存取) 
    TStringStream     (处理内存中的字符串类型数据) 
    TmemoryStream     (对于工作的内存区域数据处理) 
    TBlobStream       (BLOB类型字段的数据处理) 
    TwinSocketStream  (socket的读写处理) 
    ToleStream        (COM接口的数据处理) 
    TresourceStream   (资源文件流的处理) 
    其中最常用的是TFileStream类。使用TFileStream类来存取文件,首先要建立一个实例。声明如下: 
    constructor Create(const Filename:string;Mode:Word); 
    Filename为文件名(包括路径) 
    Mode为打开文件的方式,它包括文件的打开模式和共享模式,其可能的取值和意义如下: 
    打开模式: 
    fmCreate :用指定的文件名建立文件,如果文件已经存在则打开它。 
    fmOpenRead :以只读方式打开指定文件 
    fmOpenWrite :以只写方式打开指定文件 
    fmOpenReadWrite:以写写方式打开指定文件 
    共享模式: 
    fmShareCompat :共享模式与FCBs兼容 
    fmShareExclusive:不允许别的程序以任何方式打开该文件 
    fmShareDenyWrite:不允许别的程序以写方式打开该文件 
    fmShareDenyRead :不允许别的程序以读方式打开该文件 
    fmShareDenyNone :别的程序可以以任何方式打开该文件 


    (三)资源文件 
    1)、创建资源文件 
    首先创建一个.Rc的纯文本文件。 
    格式: 资源标识符  关键字  资源文件名 

    资源标识符:程序中调用资源时的特殊标号; 
    关键字:标识资源文件类型; 
    Wave: 资源文件是声音文件; 
    RCDATA: JPEG文件; 
    AVI: AVI动画; 
    ICON: 图标文件; 
    BITMAP: 位图文件; 
    CURSOR: 光标文件; 
    EXEFILE : EXE文件 
    资源文件名:资源文件的在磁盘上存储的文件全名 

    例如: 
    myzjy exefile zjy.exe 

    2)、编译资源文件 
    在DELPHI的安装目录的/Bin下,使用BRCC32.exe编译资源文件.RC。当然,也可以将BRCC32单独拷贝到程序文档目录使用。 
    例如: 
    Brcc32 wnhoo_reg.Rc 

    3)、资源文件引用 
     
    implementation 

    {$R *.dfm} 
    {$R wnhoo_reg.Res} 
     
    4)、调用资源文件 
    (1)存取资源文件中的位图(Bitmap) 
    Image.Picture.Bitmap.Handle :=LoadBitmap(hInstance,'资源标识符'); 
    注:如果位图没有装载成功,程序仍旧执行,但是Image将不再显示图片。你可以根据LoadBitmap函数的返回值判断是否装载成功,如果装载成功返回值是非0,如果装载失败返回值是0。 

    另外一个存取显示位图的方法如下   
    Image.Picture.Bitmap.LoadFromResourceName(hInstance,'资源标识符'); 

    (2)存取资源文件中的光标 
    Screen.Cursors[]是一个光标数组,使用光标文件我们可以将定制的光标加入到这个属性中。因为默认的光标在数组中索引值是0,所以除非想取代默认光标,最好将定制的光标索引值设为1。 
    Screen.Cursors[1] :=LoadCursor(hInstance,'资源标识符'); 
    Image.Cursor :=1; 

    (3)存取资源文件中的图标 
    将图标放在资源文件中,可以实现动态改变应用程序图标。 
    Application.Icon.Handle := LoadIcon(hInstance,'资源标识符'); 

    (4)存取资源文件中的AVI 
    Animate.ResName :='MyAvi' ; //资源标识符号 
    Animate.Active :=True ; 

    (5)存取资源文件中的JPEG 
    把jpeg单元加入到uses单元中。 
    var 
    Fjpg : TJpegImage ; 
    FStream :TResourceStream ; 
    begin 
    Fjpg :=TJpegImage.Create ; 
    //TresourceStream使用 
    FStream := TResourceStream.Create (Hinstance,'资源标识符',资源类型) ; 
    FJpg.LoadFromStream (FStream) ; 
    Image.Picture.Bitmap.Assign (FJpg); 

    (6)存取资源文件中的Wave 
    把MMSystem加入uses单元中 
    PlaySound(pchar('mywav'),Hinstance,Snd_ASync or Snd_Memory or snd_Resource) ; 

    (四)INI文件操作 
    (1)  INI文件的结构: 
    ;这是关于INI文件的注释部分 
    [节点] 
    关键字=值 
    ... 
    INI文件允许有多个节点,每个节点又允许有多个关键字, “=”后面是该关键字的值(类型有三种:字符串、整型数值和布尔值。其中字符串存贮在INI文件中时没有引号,布尔真值用1表示,布尔假值用0表示)。注释以分号“;”开头。 

    (2)  INI文件的操作 
    1、  在Interface的Uses节增加IniFiles; 
    2、  在Var变量定义部分增加一行:inifile:Tinifile;然后,就可以对变量myinifile进行创建、打开、读取、写入等操作了。 
    3、  打开INI文件:inifile:=Tinifile.create('tmp.ini'); 
    4、  读取关键字的值: 
    a:=inifile.Readstring('节点','关键字',缺省值);// string类型 
    b:=inifile.Readinteger('节点','关键字',缺省值);// integer类型 
    c:=inifile.Readbool('节点','关键字',缺省值);// boolean类型 
    其中[缺省值]为该INI文件不存在该关键字时返回的缺省值。 
    5、  写入INI文件: 
    inifile.writestring('节点','关键字',变量或字符串值); 
    inifile.writeinteger('节点','关键字',变量或整型值); 
    inifile.writebool('节点','关键字',变量或True或False); 
    当这个INI文件的节点不存在时,上面的语句还会自动创建该INI文件。 
    6、  删除关键字: 
    inifile.DeleteKey('节点','关键字');//关键字删除 
    inifile.EraseSection('节点');// 节点删除 
    7、  节点操作: 
    inifile.readsection('节点',TStrings变量);//可将指定小节中的所有关键字名读取至一个字符串列表变量中; 
    inifile.readsections(TStrings变量);//可将INI文件中所有小节名读取至一个字符串列表变量中去。 
    inifile.readsectionvalues('节点',TStrings变量);//可将INI文件中指定小节的所有行(包括关键字、=、值)读取至一个字符串列表变量中去。 
    8、  释放:inifile.distory;或inifile.free; 

    (五)文件关联 
    uses 
    registry, shlobj; 
    //实现关联注册 
    procedure Tmyzip.regzzz; 
    var 
    reg: TRegistry; 
    begin 
    reg := TRegistry.Create; 
    reg.RootKey := HKEY_CLASSES_ROOT; 
    reg.OpenKey('.zzz', true); 
    reg.WriteString('', 'myzip'); 
    reg.CloseKey; 
    reg.OpenKey('myzip/shell/open/command', true); 
    //用于打开.zzz文件的可执行程序 
    reg.WriteString('', '"' + application.ExeName + '" "%1"'); 
    reg.CloseKey; 
    reg.OpenKey('myzip/DefaultIcon',true); 
    //取当前可执行程序的图标为.zzz文件的图标 
    reg.WriteString('',''+application.ExeName+',0'); 
    reg.Free; 
    //立即刷新 
    SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil); 

    end; 

    2.3、加密压缩的实现 
    1、  生成INI临时加密文件 
    用于加密的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中建立的文件,生成资源文件 
    3.  将资源文件放到本文中这个压缩工具的程序中一起编译。 
    4.  通过将资源文件与压缩文件的合并,生成自解压文件。 
    自解压文件结构图: 


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

    2.6 系统程序设计 


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

    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 
    { protected declarations here } 
    public 
    procedure regzzz; 
    procedure ys_file(infileName, outfileName: string;password:pass;isjm:boolean;ysbz:integer); 
    function jy_file(infileName: string;password:pass=''):boolean; 
    procedure zjywj(var filename:string); 
    constructor Create; 
    destructor Destroy; override; 
    { public declarations here } 
    published 
    { published declarations here } 
    end; 

    implementation 

    constructor Tmyzip.Create; 
    begin 
    inherited Create; // 初始化继承下来的部分 
    end; 

    //##################################################### 
    //原文件加密 
    procedure jm_File(vfile:string;var 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 
    //打开需要 [加密压缩文件] 
    tmpstream:=TFileStream.Create(vFile,fmOpenread or fmShareExclusive); 
    try 
    //向 [临时加密压缩文件流] 尾部写入 [原文件流] 
    Target.Seek(0,soFromEnd); 
    Target.CopyFrom(tmpstream,0); 
    //取得文件路径 ,生成 [INI加密压缩信息文件] 
    filename:=ExtractFilePath(paramstr(0))+'tmp.in_'; 
    inifile:=TInifile.Create(filename); 
    inifile.WriteString('file1','filename',ExtractFileName(vFile)); 
    inifile.WriteString('file1','password',password); 
    inifile.WriteInteger('file1','filesize',Target.Size); 
    inifile.WriteDateTime('file1','fileDate',now()); 
    inifile.WriteBool('file1','isjm',isjm); 
    inifile.Free ; 
    //读入 [INI加密压缩信息文件流] 
    inistream:=TFileStream.Create(filename,fmOpenread or fmShareExclusive); 
    try 
    //继续在 [临时加密压缩文件流] 尾部加入 [INI加密压缩信息文件] 
    inistream.Position :=0; 
    Target.Seek(0,sofromend); 
    Target.CopyFrom(inistream,0); 
    //计算当前 [INI加密压缩信息文件] 的大小 
    FileSize:=inistream.Size ; 
    //继续在 [临时加密文件尾部] 加入 [INI加密压缩信息文件] 的SIZE信息 
    Target.WriteBuffer(FileSize,sizeof(FileSize)); 
    finally 
    inistream.Free ; 
    deletefile(filename); 
    end; 
    finally 
    tmpstream.Free; 
    end; 


    end; 

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

    //流压缩 
    procedure ys_stream(instream, outStream: TStream;ysbz:integer); 
    { 
    instream: 待压缩的已加密文件流 
    outStream  压缩后输出文件流 
    ysbz:压缩标准 
    } 
    var 
    ys: TCompressionStream; 
    begin 
    //流指针指向头部 
    inStream.Position := 0; 
    //压缩标准的选择 
    case ysbz of 
    1:  ys := TCompressionStream.Create(clnone,OutStream);//不压缩 
    2:  ys := TCompressionStream.Create(clFastest,OutStream);//快速压缩 
    3:  ys := TCompressionStream.Create(cldefault,OutStream);//标准压缩 
    4:  ys := TCompressionStream.Create(clmax,OutStream); //最大压缩 
    else 

    ys := TCompressionStream.Create(clFastest,OutStream); 
    end; 

    try 
      //压缩流 
      ys.CopyFrom(inStream, 0); 
    finally 
      ys.Free; 
    end; 
    end; 

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


    //流解压 
    procedure jy_Stream(instream, outStream: TStream); 
    { 
    instream :原压缩流文件 
    outStream:解压后流文件 
    } 
    var 
    jyl: TDeCompressionStream; 
    buf: array[1..512] of byte; 
    sjread: integer; 
    begin 
    inStream.Position := 0; 
    jyl := TDeCompressionStream.Create(inStream); 
    try 
      repeat 
        //读入实际大小 
        sjRead := jyl.Read(buf, sizeof(buf)); 
        if sjread > 0 then 
          OutStream.Write(buf, sjRead); 
      until (sjRead = 0); 
    finally 
      jyl.Free; 
    end; 
    end; 


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

    //实现关联注册 
    procedure Tmyzip.regzzz; 
    var 
    reg: TRegistry; 
    begin 
    reg := TRegistry.Create; 
    reg.RootKey := HKEY_CLASSES_ROOT; 
    reg.OpenKey('.zzz', true); 
    reg.WriteString('', 'myzip'); 
    reg.CloseKey; 
    reg.OpenKey('myzip/shell/open/command', true); 
    //用于打开.zzz文件的可执行程序 
    reg.WriteString('', '"' + application.ExeName + '" "%1"'); 
    reg.CloseKey; 
    reg.OpenKey('myzip/DefaultIcon',true); 
    //取当前可执行程序的图标为.zzz文件的图标 
    reg.WriteString('',''+application.ExeName+',0'); 
    reg.Free; 
    //立即刷新 
    SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil); 

    end; 

    //压缩文件 
    procedure Tmyzip.ys_file(infileName, outfileName: string;password:pass;isjm:boolean;ysbz:integer); 
    { 
    infileName://需要压缩加密的文件 
    outfileName://压缩加密后产生的文件 
    password://解压密码 
    ysbz://压缩标准 
    } 
    var 
    instream:TMemoryStream;   //文件加密后的临时流 
    outStream: TFileStream;   //压缩输出文件流 

    begin 
      //创建 [文件加密后的临时流] 
      instream:=TMemoryStream.Create; 
      //文件加密 
      jm_file(infileName,instream,password,isjm); 
      //创建压缩输出文件流 
      outStream := TFileStream.create(outFIleName, fmCreate); 
      try 
       //[文件加密后的临时流] 压缩 
       ys_stream(instream,OutStream,ysbz); 
      finally 
        OutStream.free; 
        instream.Free ; 
      end; 
    end; 

    //解压文件 
    function Tmyzip.jy_file(infileName: string;password:pass=''):boolean; 
    var 
    inStream,inistream,filestream_ok: TFileStream; 
    { 
    instream://解压文件名称 
    inistream://INI临时文件流 
    filestream_ok://解压OK的文件 
    } 
    outStream:tmemorystream;  //临时内存流 
    inifile:TINIFILE; //临时INI文件 
    FileSize:integer;  //密码文件的SIZE 
    resultvalue:boolean;//返回值 

    begin 

    try 
    inStream := TFileStream.create(inFIleName, fmOpenRead); 

    try 
      outStream := tmemorystream.create; 
      try 
        jy_stream(insTream,OutStream); 
        //生成临时INI文件 
           inistream:=TFileStream.create(ExtractFilePath(paramstr(0))+'tmp.in_', fmCreate); 
           try 
              //指向存储解码信息的INTEGER型变量位置 
              OutStream.Seek(-sizeof(FileSize),sofromend); 
              //读入变量信息 
              OutStream.ReadBuffer(FileSize,sizeof(FileSize)); 
              //指向解码信息位置 
              OutStream.Seek(-(FileSize+sizeof(FileSize)),sofromend); 
              //将解码信息读入INI流中 
              inistream.CopyFrom(OutStream,FileSize); 
              //释放INI文件流 
              inistream.Free ; 
              //读入INI文件信息 
              inifile:=TINIFILE.Create(ExtractFilePath(paramstr(0))+'tmp.in_'); 
              resultvalue:=inifile.ReadBool('file1','isjm',false); 
              if resultvalue then 
              begin 
                 if inifile.ReadString ('file1','password','')=trim(password) then 
                 resultvalue:=true 
                 else 
                 resultvalue:=false; 
              end 
              else 
              resultvalue:=true; 

              if resultvalue then 
              begin 

                 filestream_ok:=TFileStream.create(ExtractFilePath(paramstr(1))+inifile.ReadString('file1','filename','wnhoo.zzz'),fmCreate);
                 try 
                 OutStream.Position :=0; 
                 filestream_ok.CopyFrom(OutStream,inifile.ReadInteger('file1','filesize',0)); 
                 finally 
                 filestream_ok.Free ; 
                end; 

              end; 


             inifile.Free; 
           finally 
            //删除临时INI文件 
           deletefile(ExtractFilePath(paramstr(0))+'tmp.in_'); 
           end; 
        // 
      finally 
        OutStream.free; 
      end; 
    finally 
      inStream.free; 
    end; 
    except 
    resultvalue:=false  ; 

    end; 
    result:=resultvalue; 
    end; 


    //自解压创建 
    procedure tmyzip.zjywj(var filename:string); 
    var 
    myRes: TResourceStream;//临时存放自解压EXE文件 
    myfile:tfilestream;//原文件流 
    xfilename:string;//临时文件名称 
    file_ok:tmemorystream; //生成文件的内存流 
    filesize:integer; //原文件大小 
    begin 
    if FileExists(filename) then 
    begin 
    //创建内存流 
    file_ok:=tmemorystream.Create ; 
    //释放资源文件-- 自解压EXE文件 
    myRes := TResourceStream.Create(Hinstance, 'myzjy', Pchar('exefile')); 
    //将原文件读入内存 
    myfile:=tfilestream.Create(filename,fmOpenRead); 
    try 

    myres.Position:=0; 
    file_ok.CopyFrom(myres,0); 
    file_ok.Seek(0,sofromend); 
    myfile.Position:=0; 
    file_ok.CopyFrom(myfile,0); 
    file_ok.Seek(0,sofromend); 
    filesize:=myfile.Size; 
    file_ok.WriteBuffer(filesize,sizeof(filesize)); 
    file_ok.Position:=0; 
    xfilename:=ChangeFileExt(filename,'.exe') ; 
    file_ok.SaveToFile(xfilename); 

    finally 
    myfile.Free ; 
    myres.Free ; 
    file_ok.Free ; 

    end; 
    DeleteFile(filename); 
    filename:=xfilename; 

    end; 
    end; 

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

    destructor Tmyzip.Destroy; 
    begin 

    inherited Destroy; 
    end; 
    end. 

    3 、结束语 
    Delphi的全新可视化编程环境,为我们提供了一种方便、快捷的Windows应用程序开发工具。对于程序开发人员来讲,使用Delphi开发应用软 件,无疑会大大地提高编程效率。在delphi中可以很方便的利用流实现文件处理、动态内存处理、网络数据处理等多种数据形式,写起程序也会大大提高效率 的。
  • 相关阅读:
    LRU算法实现 最近最久未使用
    快速排序
    redis 常用命令
    实例:接口并发限流RateLimiter
    Hadoop伪分布式安装
    ssl免密登录(centos6)
    Linux下安装jdk-7u67-linux-x64.rpm
    Mosquitto安装和使用
    MQTT linux centOS7 部署
    CentOS更换yum源
  • 原文地址:https://www.cnblogs.com/luckForever/p/7254866.html
Copyright © 2020-2023  润新知