📄 adobackup.pas
字号:
// ************************ ADOBackUP ******************************
//
// 引用外部控件: BackUp ------ 可实现多个文件压缩成单一文文件
// DialogEx ---- 可预览的 Dialog
// 更新功能:
// 2001.3.15
// 包文件的名称定为Save.dat,后面依次为:Save1.dat,Save2.dat ....
// 增加删除数据选项,可自动删除旧数据,也可传递通过传递SQl删除。
// 增加数据包信息,使用户可以随数据包传送文本信息,以便终端识别。
//
// 2001.2.21
// 备份 Backup : 根据读取的外部Sql语句,备份数据,生成备份文件。
// 可根据需要,分割备份文件,可直接用A盘存储。
// 恢复 Restore : 选择备份文件,可自动合并在同一目录的文件。
// 根据条件恢复相关数据。
// 备份、恢复过程有进度提示。
//
// 2001.4.4
// 备份文件格式改变:不再存储 Info.Txt,而是存放于备份文件头
//
// 注意:作为备份依据的字段,如果修改,则可能造成数据重复或不能正确入库
//
//********************************************************************
unit ADOBackUP;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Db, ADODB, FileCtrl, Backup, DialogEx;
type
TFloppyFileHead = record
ID: array[0..3] of char; // 文件标志, 正常为 JSFB 四个字符
SerialNo: Double; // 序列号
FloppyCount: Smallint; // 磁盘总数
CurFloppyNo: Smallint; // 当前磁盘号
FileSize: integer; // 文件大小
FileName: string[60]; // 原始文件名
Information: array[0..43] of char; // 附加信息
end;
TErrorType = (etCancel, etError);
TReturnType = (rtAll, rtTable, rtSql);
TRatioChangedEvent = procedure(Sender: TObject; Ratio: Integer) of object;
TADOBackUP = class(TComponent)
private
{ Private declarations }
FPackSize: Integer; // 每个包文件的大小
FBackUpFileName: string; // 包文件名
FTempPath, FSavePath, FWorkPath, FOrigPath: string; // 临时目录
FSourceFile: string; // 含路径
FADOConnection: TADOConnection; // 数据库源
FSQLStrings: TStrings; // Sql语句
FDelSQLStrings: TStrings; // 传递删除Sql语句
FInfo: TStrings; // 附带信息
TableMaps: TStrings; // 文件名映射
FIsDevide: Boolean; // 是否分割文件
FIsSavetoA: Boolean;
FRadio: integer; // 拷贝进度
FRatioChanged: TRatioChangedEvent;
FAutoDel: Boolean; // 是否自动删除数据
FFloppyFileHead: TFloppyFileHead;
FFileHeadList: array of TFloppyFileHead;
FErrorType: TErrorType;
BackupFile: TBackupFile;
function StartWrong: Boolean;
function CopyDevide: Boolean; // 拷贝分割文件
function CopyFloopyFile: Boolean; // 将文件进行分割
function MergeFloopyFile: Boolean; // 将文件进行合并
procedure CalFloppyHeadList; // 计算每包文件头(分割拷贝前准备)
procedure RemoveDir(DirName: string); // 删除临时单层目录
function CopyfromAtoTemp: Boolean; // 将文件从A转移至临时目录
function CopytoTemp(SourcePath: string): Boolean; // 文件转移至临时目录
function RestoreData: Boolean; // 更新数据库
function GetTableName(mSql: TStrings; ReturnType: TReturnType = rtAll): TStrings;
procedure RebackFiles(mfileName: string); // 恢复文件
procedure SetSqlStrings(Value: TStrings);
procedure SetDelSQLStrings(Value: TStrings);
procedure SetInfo(Value: TStrings);
function GenerateTempName(Path: string): string;
procedure PreviewFile(Sender: TOpenPreviewDialog; FileName: string);
// Function CopyFromSource:Boolean; // 从备份转移文件
protected
{ Protected declarations }
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function Backup(SavePath: string): Boolean;
function Restore(SourceFile: string): Boolean;
function GetInfo(SourceFile: string): Boolean; // 是否合法的备份文件
function BrowseBackFile: string;
published
{ Published declarations }
property AutoDel: Boolean read FAutoDel write FAutoDel default True;
property Info: TStrings read FInfo write SetInfo;
property PackSize: Integer read FPackSize write FPackSize default 1456000;
property BackUpFileName: string read FBackUpFileName write FBackUpFileName;
property ADOConnection: TADOConnection read FADOConnection write FADOConnection;
property SQLStrings: TStrings read FSQLStrings write SetSqlStrings;
property DelSQLStrings: TStrings read FDelSQLStrings write SetDelSQLStrings;
property IsDevide: Boolean read FIsDevide write FIsDevide;
property Procession: TRatioChangedEvent read FRatioChanged write FRatioChanged;
end;
procedure Register;
implementation
const
fn_TableMap = '_TblMap.txt';
fn_SQLFile = '_SQL.Txt';
BackupSign = #$AA#$55#0'SWAT';
procedure Register;
begin
RegisterComponents('FVCL', [TADOBackUP]);
end;
procedure TADOBackUp.SetSqlStrings(Value: TStrings);
begin
if Assigned(Value) then
FSqlStrings.Assign(Value);
end;
procedure TADOBackUp.SetDelSQLStrings(Value: TStrings);
begin
if Assigned(Value) then
FDelSqlStrings.Assign(Value);
end;
procedure TADOBackup.SetInfo(Value: TStrings);
begin
if Assigned(Value) then
FInfo.Assign(Value);
end;
// 在指定路径(Path)下生成唯一的临时文件名
function TADOBackup.GenerateTempName(Path: string): string;
function IntToBase32(Number: Longint): string;
const
Table: array[0..31] of Char = '0123456789ABCDEFGHIJKLMNOPQRSTUV';
var
I: Integer;
begin
Result := '';
for I := 0 to 4 do
begin
Insert(Table[Number and 31], Result, 1);
Number := Number shr 5;
end;
end;
var
Rand, RandOrig: Longint;
begin
RandOrig := Random($2000000);
Rand := RandOrig;
repeat
Inc(Rand);
if Rand > $1FFFFFF then Rand := 0;
if Rand = RandOrig then
raise Exception.Create('建立临时文件失败');
Result := 'Dat' + IntToBase32(Rand);
until not FileExists(Path + Result);
end;
function TADOBackup.GetInfo(SourceFile: string): Boolean; // 是否合法的备份文件
var
mReadFile: file of Byte;
InfoLen: Integer;
InfoText: string;
begin
Assignfile(mReadFile, SourceFile);
InfoText := '';
Result := False;
try
try
ReSet(mReadFile);
if not Eof(mReadFile) then
BlockRead(mReadFile, FFloppyFileHead, Sizeof(TFloppyFileHead));
if FFloppyFileHead.ID <> 'JSFB' then // 表明不是经过处理后的包文件
ReSet(mReadFile);
SetLength(InfoText, Length(BackUpSign));
BlockRead(mReadFile, InfoText[1], Length(BackUpSign));
if InfoText = BackUpSign then
begin
Result := True;
BlockRead(mReadFile, InfoLen, Sizeof(Integer));
SetLength(InfoText, InfoLen);
BlockRead(mReadFile, InfoText[1], InfoLen);
end;
finally
CloseFile(mReadFile);
end;
except
end;
FInfo.Text := InfoText;
end;
function TADOBackup.GetTableName(mSql: TStrings; ReturnType: TReturnType = rtAll): TStrings;
function PosStr(substr: string; s: string): Integer; //
begin
s := stringReplace(s, substr, '^', [rfIgnoreCase]);
Result := Pos('^', s);
end;
var
i: integer;
Sqltxt: string;
posint: integer;
mtableName, mtablesql: string;
begin
Result := Tstringlist.Create;
for i := 0 to mSql.Count - 1 do
begin
Sqltxt := mSql[i];
posint := posstr('from', Sqltxt);
if posint <> 0 then
begin
delete(sqltxt, 1, posint + 4); // 删去空格
mtableName := copy(Sqltxt, 1, pos(' ', Sqltxt) - 1);
posint := posstr('Where', Sqltxt);
mtablesql := '';
if posint = 0 then
mtableName := SqlTxt
else
begin
delete(sqltxt, 1, posint + 5);
mtablesql := 'Where ' + Copy(Sqltxt, 1, length(Sqltxt));
end;
case ReturnType of
rtAll:
begin
if posint <> 0 then
mtablesql := ',' + mtablesql;
Result.Add(mtableName + mtablesql);
end;
rtTable:
Result.Add(mtableName);
rtSql:
Result.Add(mtablesql);
end;
end;
end;
end;
function TADOBackup.MergeFloopyFile: Boolean;
var
SFile: string;
tmpS: string;
ErrorFlag: Boolean;
SHandle, THandle: Integer;
i, j: integer;
BlockCount, LastBlockSize: integer;
Buffers: array[0..4095] of char;
Excursion: Integer;
TempFileName: string;
begin
Result := True;
ErrorFlag := False;
TempFileName := FOrigPath + FBackUpFileName;
THandle := FileCreate(TempFileName);
SHandle := -1;
SFile := StringReplace(FBackUpFileName, '.', InttoStr(1) + '.', [rfReplaceAll, rfIgnoreCase]);
SFile := fTempPath + SFile;
for i := 0 to Length(FFileHeadList) - 1 do
begin
TempFileName := ExtractFileName(SFile);
Excursion := Length(inttostr(i + 1)) + 1; // 计算.偏移位数
if i = 0 then
SFile := ExtractFilePath(SFile) + Copy(TempFileName, 1, pos('.', TempFileName) - Excursion)
+ ExtractFileExt(SFile)
else if i = 1 then
SFile := ExtractFilePath(SFile) + Copy(TempFileName, 1, pos('.', TempFileName) - 1)
+ Inttostr(i + 1) + ExtractFileExt(SFile)
else
SFile := ExtractFilePath(SFile) + Copy(TempFileName, 1, pos('.', TempFileName) - Excursion)
+ Inttostr(i + 1) + ExtractFileExt(SFile);
if FileExists(SFile) then
begin
SHandle := FileOpen(SFile, fmOpenRead or fmShareDenyNone);
if SHandle = -1 then
begin
tmpS := '读备份数据 ' + IntToStr(i + 1) + ' 号盘错误, ';
ErrorFlag := True;
Break;
end;
end
else
begin
tmpS := '没有发现备份数据 ' + IntToStr(i + 1) + ' 号盘, ';
ErrorFlag := True;
Break;
end;
// 设置读写缓冲区大小
BlockCount := (FFileHeadList[i].FileSize - Sizeof(TFloppyFileHead)) div 4096;
LastBlockSize := (FFileHeadList[i].FileSize - Sizeof(TFloppyFileHead)) mod 4096;
FileSeek(SHandle, Sizeof(TFloppyFileHead), 0);
for j := 1 to BlockCount do
begin
FileRead(SHandle, Buffers, 4096);
FileWrite(THandle, Buffers, 4096);
end;
if LastBlockSize > 0 then
begin
FileRead(SHandle, Buffers, LastBlockSize);
FileWrite(THandle, Buffers, LastBlockSize);
end;
FileClose(SHandle);
DeleteFile(SFile);
end;
FileClose(THandle);
if ErrorFlag then
Result := False;
end;
procedure TADOBackup.RemoveDir(DirName: string);
var
FSearchRec: TSearchRec;
FindResult: integer;
begin
try
FindResult := FindFirst(DirName + '*.*', faAnyFile + faHidden + faSysFile, FSearchRec);
try
while FindResult = 0 do
begin
Deletefile(DirName + FSearchRec.Name);
FindResult := FindNext(FSearchRec);
end;
finally
FindClose(FSearChRec);
end;
rmDir(DirName);
except
end;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -