zoukankan      html  css  js  c++  java
  • 实现软件自动升级

      原理简单,在FTP上维护一个Update.ini文件,里面记录着要更新文件的版本号,本地也有一个Update.ini文件,每次启动更新程序时,先从FTP上下载Update.ini文件到本地名字为Update_new.ini,然后比较这两个文件,如果新的版本号大于旧的,或者新的文件在就ini中没有,这些就表示要更新的文件,然后逐一下载。

        本程序名字为AutoUpdate,你生成这个exe,然后和主程序一起打包,创建桌面快捷方式时,指向AutoUpdate,而不是主程序。

        在本地还有一个ini文件,比如叫ftp.ini吧,里面内容是

    [coninfo]
    main=Project1.exe
    param={app}sayyes.pj2 -y bde.txt

    main=Project1.exe:是主程序名称,和升级程序在同一目录

    param={app}sayyes.pj2 -y bde.txt:这是命令行参数,app为当前路径,在程序中替换掉,传递给主程序(如果需要的话)

    update.ini的内容格式如下

    [root]
    办事处查询.txt=20100519
    [dbcard]
    sayyes.pj2=20100519
    FTP用户密码.txt=20100519

    [root]代表根目录,后面的[dbcard]代表子目录,依次类推

    unit Main;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, IdHTTP, IdBaseComponent, IdComponent, IdTCPConnection,
      IdTCPClient, IdFTP, ComCtrls, ExtCtrls,IniFiles,ShellAPI, jpeg;
    
    type
      TfrmMain = class(TForm)
        IdFTP1: TIdFTP;
        IdHTTP1: TIdHTTP;
        ProgressBar1: TProgressBar;
        GroupBox1: TGroupBox;
        ld_host: TLabeledEdit;
        ld_username: TLabeledEdit;
        ld_psw: TLabeledEdit;
        ld_port: TLabeledEdit;
        Label1: TLabel;
        cb_mode: TComboBox;
        ProgressBar2: TProgressBar;
        Label3: TLabel;
        list_file: TListView;
        Label4: TLabel;
        procedure IdFTP1Work(Sender: TObject; AWorkMode: TWorkMode;
          const AWorkCount: Integer);
        procedure IdFTP1WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
        procedure FormCreate(Sender: TObject);  private
        { Private declarations }
        FSize:Integer;
        FPath: string;
        FExePath: string;
        FInitPath: string;
        FIniFile:TIniFile;
        FHandle:HWND;
        FMainExe:string;
        FParam: string;
    
        procedure CheckUpdateList;
        function ConnectFTP:Boolean;
        procedure DownLoadFile;
        procedure LoadIni;
        procedure SaveIni;
      public
        { Public declarations }
      end;
    
    var
      frmMain: TfrmMain;
    
    implementation
    uses
      Flash;
    {$R *.dfm}
    //下载进度
    procedure TfrmMain.IdFTP1Work(Sender: TObject; AWorkMode: TWorkMode;
      const AWorkCount: Integer);
    begin
      ProgressBar1.Position := AWorkCount;
      Application.ProcessMessages;
    end;
    
    procedure TfrmMain.IdFTP1WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
    begin
      ProgressBar1.Position := 0;
      ProgressBar2.StepBy(1);
    end;
    
    procedure TfrmMain.FormCreate(Sender: TObject);
    var
      frm: TfrmFlash;
    begin
      Self.Visible := False;
      //闪屏,可以不加
      frm := TfrmFlash.Create(nil);
      frm.Show;
      Application.ProcessMessages;
      FExePath := ExtractFilePath(Application.ExeName);
      FIniFile := TIniFile.Create(FExePath+'ftp.ini');
      //加载ini信息,就是主机和端口之类的信息
      LoadIni;
      try
        ConnectFTP;
        CheckUpdateList;
        Self.Visible := True;
        Application.ProcessMessages;
        DownLoadFile;
      finally
        
        FreeAndNil(frm);
        IdFTP1.Quit;
        FParam := StringReplace(FParam,'{app}',FExePath,[rfReplaceAll]);
    //更新完毕后,启动主程序,并传入命令行参数
        ShellExecute(Handle,'open',PChar(FExePath+FMainExe),PChar(FParam),nil,SW_NORMAL);
        Application.Terminate;
      end;
    end;
    
    //检查更新列表
    procedure TfrmMain.CheckUpdateList;
    var
      oldFile,newFile:TStringList;
      i,ver,index:Integer;
      itemstr,itempath: string;
      item:TListItem;
    begin
      oldFile := TStringList.Create;
      newFile := TStringList.Create;
      try
        list_file.Clear;
        //先下载服务器上的update.ini文件,存到本地update_new.ini
        IdFTP1.Get('update.ini',FExePath+'update_new.ini',True);
        if FileExists(FExePath + 'update.ini') = False then Exit;
        oldFile.LoadFromFile(FExePath + 'update.ini');
        newFile.LoadFromFile(FExePath + 'update_new.ini');
        itempath := '';
        //下面开始比较两个list,如果newFile的版本号大于oldFile的版本号或者oldFile中没有的都表示要更新的
        for i := 0 to newFile.Count - 1 do
        begin
          itemstr := newFile.Strings[i];
          if itemstr = '' then Continue;
          if itemstr[1] = '[' then
          begin
            itempath := Copy(itemstr,2,Length(itemstr)-2);
            //如果是根目录
            if itempath = 'root' then
              itempath := '/';
            Continue;
          end;
          itemstr := newFile.Names[i];
          index := oldFile.IndexOfName(itemstr);
          if index = - 1 then
          begin
            item := list_file.Items.Add;
            item.Caption := itemstr;
            item.SubItems.Add(itempath)
          end
          else
          begin
            ver := StrToIntDef(newFile.Values[itemstr],0);
            if ver > StrToIntDef(oldFile.Values[itemstr],0) then
            begin
              item := list_file.Items.Add;
              item.Caption := itemstr;
              item.SubItems.Add(itempath);
            end;
          end;
        end;
        if list_file.Items.Count = 0 then Application.Terminate;
      finally
        oldFile.Free;
        newFile.Free;
      end;
    end;
    
    function TfrmMain.ConnectFTP: Boolean;
    begin
      Result := False;
      try
      IdFTP1.Host := ld_host.Text;
      IdFTP1.Port := StrToIntDef(ld_port.Text,21);
      IdFTP1.Username := ld_username.Text;
      IdFTP1.Password := ld_psw.Text;
      IdFTP1.Connect;
      IdFTP1.Passive := cb_mode.ItemIndex = 1;
      FInitPath := IdFTP1.RetrieveCurrentDir;
      Result := IdFTP1.Connected;
      except
        Result := False;
      end;
    end;
    
    //下载文件更新
    procedure TfrmMain.DownLoadFile;
    var
      i:Integer;
      path:string;
      s1,s2:String;
    begin
      ProgressBar2.Max := list_file.Items.Count;
      ProgressBar2.Position := 0;
      FIniFile.EraseSection('error');
      for i := 0 to list_file.Items.Count - 1 do
      begin
        Label4.Caption := '正在下载 '+list_file.Items[i].Caption;
        Application.ProcessMessages;
        IdFTP1.ChangeDir(FInitPath);
        path := list_file.Items[i].SubItems.Strings[0];
        if path <>'/' then
        begin
          IdFTP1.ChangeDir(path);
          ForceDirectories(FExePath+path);
          s1 := list_file.Items[i].Caption;
          s2 := FExePath+path+'/'+list_file.Items[i].Caption;
          IdFTP1.Get(s1,s2,True);
        end
        else
        begin
          s1 := list_file.Items[i].Caption;
          s2 := FExePath+'/'+list_file.Items[i].Caption;
          IdFTP1.Get(s1,s2,True);
          //记录失败项
          FIniFile.WriteString('error',list_file.Items[i].Caption,'成功');
        end;
        except
          //记录失败项
          FIniFile.WriteString('error',list_file.Items[i].Caption,'失败');
        end;
      end;
      Label4.Caption := '所有文件更新完毕!';
      DeleteFile(FExePath+'update.ini');
      CopyFile(PChar(FExePath+'update_new.ini'),PChar(FExePath+'update.ini'),False);
    end;
    
    procedure TfrmMain.LoadIni;
    begin
      ld_host.Text := FIniFile.ReadString('coninfo','host','******');
      ld_username.Text := FIniFile.ReadString('coninfo','user','******');
      ld_psw.Text := FIniFile.ReadString('coninfo','psw','******');
      ld_port.Text := FIniFile.ReadString('coninfo','port','21');
      cb_mode.ItemIndex := FIniFile.ReadInteger('coninfo','mode',1);
      FMainExe := FIniFile.ReadString('coninfo','main','Main.exe');
      FParam := FIniFile.ReadString('coninfo','param','');
    end;
    
    procedure TfrmMain.SaveIni;
    begin
      FIniFile.WriteString('coninfo','host',ld_host.Text);
      FIniFile.WriteString('coninfo','user',ld_username.Text);
      FIniFile.WriteString('coninfo','psw',ld_psw.Text);
      FIniFile.WriteString('coninfo','port',ld_port.Text);
      FIniFile.WriteInteger('coninfo','mode',cb_mode.ItemIndex);
    end;
    
    end.
    View Code
  • 相关阅读:
    用MySQL 生成随机密码增加大写处理
    【100题】第三十八 (天平称重、大输入流、去除重复URL)
    【编程珠玑】代码优化的27条经典法则
    cocos2dx:如何快速屏蔽触摸
    【2012百度之星资格赛】A:百度计算器的加法
    【2012百度之星资格赛】C:易手机的套餐
    去掉xcode编译warning:ld: warning: directory not found for option 'L
    【2012百度之星资格赛】D:共同狂欢
    【windows8开发】回复g10589119提出的问题(c#调用C++/CX dll)
    linux shell 之在线文本编辑sed
  • 原文地址:https://www.cnblogs.com/key-ok/p/3429864.html
Copyright © 2011-2022 走看看