怎样用程序代码实现把数据库备份导出为一个*.DAT文件,并可选择压缩备份,再怎恢复? 500分相送!!!!!(200分)

  • 主题发起人 主题发起人 pokar
  • 开始时间 开始时间
P

pokar

Unregistered / Unconfirmed
GUEST, unregistred user!
怎样用程序代码实现把数据库备份导出为一个*.DAT文件,并可选择压缩备份,再怎恢复? 500分相送!!!!!
 
各种大型数据都有导出和备份机制,多数的备份还有压缩功能。
如果你要做通用的导出功能,可以将数据导出到各种桌面数据库格式(*.db, *.dbf等),
或者XML及TXT等,.Dat并不是任何具有特征的文件类型。压缩方式需要去查找各种格式的
压缩控件来支持。
 
1、如果你直接备份成数据库管理系统支持的备份格式,你只有使用数据库管理系统提供的
数据备份命令来做了
2、是否可以考虑把数据库中的表,在客户端通过table控件或者是query控件,来实现数据
备份,把数据导出成文本文件,利用第三方压缩控件把所有的数据文件压缩成一个文件
其恢复过程首先解压缩,然后把指定的数据文件通过insert语句实现数据的再造
 
下面是Sql Server的备份恢复。使用Sql语句。
// 备份。使用AdoConnection连接你的数据库,adoquery链这个AdoConnection。
procedure TForm1.Button1Click(Sender: TObject);
begin
AdoQuery1.SQL.Text := 'backup database testDFW to disk = ' + '''' + 'e:/backup.dat' + '''';
showmessage(AdoQuery1.SQL.Text);
AdoQuery1.ExecSQL;
end;
//恢复。 AdoConnection不要连接你的数据库,可以连接一个其他数据库,如Master。
procedure TForm1.Button2Click(Sender: TObject);
begin
AdoQuery1.SQL.Text := 'restore database testDFW from disk =' + '''' + 'e:/backup.dat' + '''';
showmessage(AdoQuery1.SQL.Text);
AdoQuery1.ExecSQL;
end;
 
Ganquan说的还是比较实用的,我也经常这么干。
 
对不起,我忘说了用的是ado+access
 
1、使用压缩控件,如ZIPTV等
2、把你要备份的内容用SQL导出来存成你定义的格式,并压缩
3、恢复时先解压,然后从文件读出内容并导入原数据表
 
利用一个叫BACKFILE的压缩组件,直接对MDB进行压缩另存,就可以了,何必非要对ACCESS进行数据备份呢。多此一举啊。
 
可以在DELPHI中用OLE来调用ACCESS的导入导出工具。我以前回答过一个同样的问题。
 
下面的是实现,控件及界面部分请参阅http://wolfsoft.nugoo.com/download/backup.asp:
控件代码:
// ************************ 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;
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.FileSize - Sizeof(TFloppyFileHead)) div 4096;
LastBlockSize := (FFileHeadList.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;

function TADOBackup.CopyFloopyFile: Boolean;
var
i, j: integer;
SHandle, THandle: Integer;
FloppySize: integer;
Buffers: array[0..4095] of Char;
BlockCount: integer;
LastBlockSize: integer;
TempFileName: string;
begin
SHandle := FileOpen(FOrigPath + FBackUpFileName, fmOpenRead or fmShareDenyNone);
for i := 0 to Length(FFileHeadList) - 1 do
begin
if i <> 0 then
TempFileName := StringReplace(FBackUpFileName, '.', InttoStr(i + 1) + '.', [rfReplaceAll, rfIgnoreCase])
else
TempFileName := FBackupFileName;
THandle := FileCreate(FWorkPath + TempFileName); // save.dat,save1.dat
if THandle = -1 then
begin
Result := False;
FileClose(SHandle);
Exit;
end;
FloppySize := FFileHeadList.FileSize - Sizeof(TFloppyFileHead); // 获取当前文件包容量
BlockCount := FloppySize div 4096;
LastBlockSize := FloppySize mod 4096;
FileWrite(THandle, FFileHeadList, Sizeof(FFileHeadList));

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(THandle);
end;
FileClose(SHandle);
Result := True;
end;

procedure TADOBackup.CalFloppyHeadList;
var
i: integer;
CompPackSize, LastFloppySize: integer;
FHandle: Integer;
FileMaxSize: integer;
SerialNos: Double;
begin
FHandle := FileOpen(FOrigPath + FBackUpFileName, fmOpenRead or fmShareDenyNone);
CompPackSize := Windows.GetFileSize(FHandle, @LastFloppySize); //被分包文件的大小
FileClose(FHandle);

FileMaxSize := FPackSize - Sizeof(TFloppyFileHead); // 每个包的最大容量

i := (CompPackSize + FileMaxSize - 1) div FileMaxSize; // 最多可分成多少包
SetLength(FFileHeadList, i);
LastFloppySize := CompPackSize mod FileMaxSize; //最后一个包文件的大小
SerialNos := Now; // 随即获取序列号

// 为每一个包填写抬头
for i := 0 to Length(FFileHeadList) - 2 do
begin
with FFileHeadList do
begin
ID[0] := 'J';
ID[1] := 'S';
ID[2] := 'F';
ID[3] := 'B';
SerialNo := SerialNos;
FloppyCount := Length(FFileHeadList);
CurFloppyNo := i + 1;
FileSize := FPackSize;
FileName := FBackUpFileName;
end;
end;
i := Length(FFileHeadList) - 1;
with FFileHeadList do
begin
ID[0] := 'J';
ID[1] := 'S';
ID[2] := 'F';
ID[3] := 'B';
SerialNo := SerialNos;
FloppyCount := Length(FFileHeadList);
CurFloppyNo := i + 1;
if LastFloppySize = 0 then
FileSize := FPackSize
else
FileSize := LastFloppySize + Sizeof(TFloppyFileHead);
FileName := FBackUpFileName;
end;
end;

function TADOBackup.RestoreData: Boolean;
var
mADODataSet, mUpdateDataSet: TADODataSet;
mADOCommand: TADOCommand;
Bufs, Buftable, BufSql: TStrings;
i, m: integer;
TotalCount, NowCount: Integer;
begin
// Result := False;
mADODataSet := TADODataSet.Create(nil);
mADODataSet.Connection := FADOConnection;
mUpdateDataSet := TADODataSet.Create(nil);
mUpdateDataSet.Connection := FADOConnection;
mADOCommand := TADOCommand.Create(nil);
mADOCommand.Connection := FADOConnection;
Bufs := TStringList.Create;

Bufs.LoadFromFile(fTempPath + fn_SQLFile);
TableMaps.LoadFromFile(fTempPath + fn_TableMap);
Buftable := GetTableName(Bufs, rtTable);
BufSql := GetTableName(Bufs, rtSql);
TotalCount := 0;
NowCount := 0;
try
try
with mADODataSet do
begin
for i := 0 to BUfs.Count - 1 do
begin
Close;
LoadFromFile(fTempPath + TableMaps);
Open;
TotalCount := TotalCount + RecordCount;
end;
end;
if not FAutoDel then
begin
for i := 0 to FDelSQLStrings.Count - 1 do
begin
mADOCommand.CommandText := FDelSQLStrings;
try
mADOCommand.Execute;
except
end;
end;
end;
for i := 0 to Bufs.Count - 1 do
begin
if FAutoDel then
begin
mADOCommand.CommandText := 'Delete from ' + Buftable + ' ' + BufSql;
try
mADOCommand.Execute;
except
end;
end;
mUpdateDataSet.Close;
mUpdateDataSet.CommandText := 'Select * from ' + Buftable;
mUpdateDataSet.Open;
with mADODataSet do
begin
Close;
LoadFromFile(fTempPath + TableMaps);
Open;
first;
while not Eof do
begin
inc(NowCount);
try
mUpdateDataSet.Append;
for m := 0 to mUpdateDataSet.Fields.Count - 1 do
begin
mUpdateDataSet.Fields[m].Value := Fields[m].Value;
end;
mUpdateDataSet.Post;
except
end;
if TotalCount = 0 then
FRadio := 100
else
FRadio := (100 * NowCount div Totalcount);
if Assigned(FRatioChanged) then
FRatioChanged(Self, fRadio);
Next;
end;
end;
end;
except
raise Exception.Create('数据恢复失败!')
end;
finally
mADODataSet.free;
mADOCommand.free;
mUpdateDataSet.free;
Bufs.Free;
end;
Result := True;
end;

function TADOBackup.CopyDevide: Boolean;
var
i: integer;
ErrorFlag: Boolean;
tmpSource, tmpTarget: string;
ErrorCodes: DWORD;
Tmps, TempFileName: string;
begin
Result := True;
CalFloppyHeadList; // 计算需分割为多少包
if not CopyFloopyFile then
begin
Result := False;
Exit;
end;
if not FisSavetoA then
Exit;
ErrorFlag := False;
for i := 0 to Length(FFileHeadList) - 1 do
begin
while True do
begin
if Application.MessageBox(PChar('请在 A:/ 驱中放一张空白软盘,然后按确定按钮'),
PChar('拷贝第 ' + IntToStr(i + 1) + ' 号盘'),
mb_OKCANCEL + mb_IconInformation) = mrCancel then
begin
FErrorType := etCancel;
Result := False;
Break;
end;
if i <> 0 then
TempFileName := StringReplace(FBackUpFileName, '.', InttoStr(i + 1) + '.',
[rfReplaceAll, rfIgnoreCase])
else
TempFileName := FBackupFileName;
tmpSource := FWorkPath + TempFileName; // 从工作路径里提出要拷贝的分割后的文件
tmpTarget := FSavePath + TempFileName;
if not CopyFile(PChar(tmpSource), PChar(tmpTarget), False) then
begin
ErrorCodes := GetLastError;
case ErrorCodes of
ERROR_CANNOT_MAKE: tmpS := '不能在 ' + tmpS + ' 盘创建文件,';
ERROR_ACCESS_DENIED, ERROR_READ_FAULT: tmpS := '磁盘写错误,磁盘损坏,';
ERROR_WRITE_PROTECT: tmpS := tmpS + ' 盘被写保护,';
ERROR_DISK_CHANGE, ERROR_NOT_READY: tmpS := '未插入磁盘,';
ERROR_DISK_CORRUPT: tmpS := '磁盘被损坏,';
ERROR_DISK_FULL, ERROR_HANDLE_DISK_FULL: tmpS := '磁盘空间满,';
ERROR_FLOPPY_UNKNOWN_ERROR: tmpS := '未知错误,';
ERROR_GEN_FAILURE: tmpS := '磁盘写错误,';
else
tmpS := '其他错误,';
end;
Messagebeep(0);
if Application.MessageBox(PChar('拷贝失败: ' + tmpS + '重新拷贝吗?'),
'错误', MB_OKCANCEL + MB_ICONWARNING) = mrCancel then
begin
FErrorType := etCancel;
ErrorFlag := True;
Break;
end;
end
else
Break;
end;
if ErrorFlag then
begin
Result := False;
Break;
end;
end;
end;

function TADOBackup.StartWrong: Boolean;
begin
Result := True;
if not Assigned(FADOConnection) then
begin
Application.MessageBox('请先设置ADO连接!', '系统信息', 0 + mb_Iconinformation);
exit;
end;
if not Assigned(FSQLStrings) then
begin
Application.MessageBox('请先设置SQL语句!', '系统信息', 0 + mb_Iconinformation);
exit;
end;
if BackupFileName = '' then
begin
Application.MessageBox('请先设置备份包名!', '系统信息', 0 + mb_Iconinformation);
exit;
end;
Result := False;
end;

procedure TADOBackup.RebackFiles(mfileName: string); // 恢复文件
var
mReadFile: file of TFloppyFileHead;
InfoLen: Integer;
InfoText: string;
BackUpstream: TFileStream;
begin
FSourceFile := mfileName;
Assignfile(mReadFile, FSourceFile);
ReSet(mReadFile);
try
if not Eof(mReadFile) then
Read(mReadFile, FFloppyFileHead); // 读取文件头信息
finally
CloseFile(mReadFile);
end;
if UpperCase(Copy(FSourceFile, 1, 1)) = 'A' then
FIsSavetoA := True
else
FIsSavetoA := False;
if Directoryexists(FTempPath) then
RemoveDir(FTempPath);
ForceDirectories(FTempPath);
if FFloppyFileHead.ID = 'JSFB' then // 表明是经过处理后的包文件
begin
FisDevide := True;
FBackUpFileName := FFloppyFileHead.FileName;
if FisSavetoA then
CopyfromAtoTemp
else
begin
setLength(FFileHeadList, FFloppyFileHead.FloppyCount); // 重设磁盘记录长度
CopytoTemp(ExtractFilePath(FSourceFile));
end;
MergeFloopyFile; // 还原压缩包
FSourceFile := FOrigPath + FBackUpFileName;
end
else // 原始压缩文件
begin
FisDevide := False;
FBackUpFileName := ExtractFileName(FSourceFile);
end;
BackUpstream := TFileStream.Create(FSourceFile, fmOpenRead);
BackUpstream.Position := Length(BackupSign);
BackUpstream.Read(InfoLen, sizeof(Integer));
SetLength(InfoText, InfoLen);
BackUpstream.Read(InfoText[1], InfoLen);
try
BackUpFile.RestoreFromStream(BackUpstream, FTempPath); // 直接解压到临时目录
finally
BackUpstream.Free;
end;
if FisDevide then
Deletefile(FSourceFile);
end;

function TADOBackup.Restore(SourceFile: string): Boolean;
begin
Result := False;
if StartWrong then
exit;
RebackFiles(SourceFile);

if not RestoreData then // 如果数据库更新失败
exit;
RemoveDir(FTempPath);
Result := True;
end;

function TADOBackup.CopytoTemp(SourcePath: string): Boolean;
var
FindResult: Integer;
mSearchRec: TSearchRec;
tmpSource, tmpTarget, TempFileName: string;
mReadFile: file of TFloppyFileHead;
mFloppyFileHead: TFloppyFileHead;
begin
Result := False;
FindResult := FindFirst(SourcePath + '*.*', faAnyFile + faHidden + faSysFile, mSearchRec);
try
while FindResult = 0 do
begin
TempFileName := mSearchRec.Name;
if Copy(mSearchRec.Name, 1, Pos('.', FBackUpFileName) - 1) <>
Copy(FBackUpFileName, 1, Pos('.', FBackUpFileName) - 1) then
begin
FindResult := FindNext(mSearChRec);
Continue;
end;

tmpSource := SourcePath + TempFileName; // 从工作路径里提出要拷贝的分割后的文件
Assignfile(mReadFile, tmpSource);
ReSet(mReadFile);
try
if not Eof(mReadFile) then
Read(mReadFile, mFloppyFileHead);
if mFloppyFileHead.ID = 'JSFB' then
if mFloppyFileHead.SerialNo = FFloppyFileHead.SerialNo then
FFileHeadList[mFloppyFileHead.CurFloppyNo - 1] := mFloppyFileHead;
finally
CloseFile(mReadFile);
end;

tmpTarget := FTempPath + TempFileName;
if not CopyFile(PChar(tmpSource), PChar(tmpTarget), False) then
raise Exception.Create('拷贝失败!');
FindResult := FindNext(mSearChRec);
end;
finally
findclose(mSearchRec);
end;
end;

function TADOBackup.CopyfromAtoTemp: Boolean; // 将文件从A转移至临时目录
var
FloppyCount, CurFloppy: integer;
SerialNos: Double;
SFile: string;
tmpS: string;
tempFileName: string;
Excursion: Byte;
ErrorFlag: Boolean;
// ErrorCodes: DWord;
FHandle: Integer;
begin
Result := True;
ErrorFlag := False;
// 初始化包信息
FloppyCount := 1; // 包个数
CurFloppy := 1; // 当前包
SerialNos := -1; // 包序列号
SetLength(FFileHeadList, 1);
SFile := StringReplace(FBackUpFileName, '.', InttoStr(1) + '.', [rfReplaceAll, rfIgnoreCase]);
SFile := extractFilePath(FSourceFile) + SFile;
while True do
begin
if UpperCase(Copy(SFile, 1, 1)) = 'A' then // 提示插入磁盘
begin
if CurFloppy <> 1 then
begin
if Application.MessageBox(PChar('请在 A:/ 驱中放入 ' + IntToStr(CurFloppy) +
' 号数据盘。'), '恢复数据', MB_YESNO + MB_ICONWARNING) = ID_NO then
begin
tmpS := '取消操作';
FErrorType := etCancel;
ErrorFlag := False;
Break;
end;
end;
end;

TempFileName := ExtractFileName(SFile);
Excursion := Length(inttostr(CurFloppy)) + 1; // 计算.偏移位数

if CurFloppy = 1 then
SFile := ExtractFilePath(SFile) + Copy(TempFileName, 1, pos('.', TempFileName) - Excursion)
+ ExtractFileExt(SFile)
else if CurFloppy = 2 then
SFile := ExtractFilePath(SFile) + Copy(TempFileName, 1, pos('.', TempFileName) - 1)
+ Inttostr(CurFloppy) + ExtractFileExt(SFile)
else
SFile := ExtractFilePath(SFile) + Copy(TempFileName, 1, pos('.', TempFileName) - Excursion)
+ Inttostr(CurFloppy) + ExtractFileExt(SFile);

if FileExistS(SFile) then
begin
FHandle := FileOpen(SFile, fmOpenRead or fmShareDenyNone);
if FHandle = -1 then
begin
tmpS := '读备份数据 ' + IntToStr(CurFloppy) + ' 号盘错误, ';
ErrorFlag := True;
end;
//将文件抬头读入 FFileHeadList
if FileRead(FHandle, FFileHeadList[CurFloppy - 1], Sizeof(FFileHeadList[CurFloppy - 1])) = -1 then
begin
tmpS := '读备份数据 ' + IntToStr(CurFloppy) + ' 号盘错误, ';
ErrorFlag := True;
end;
FileClose(FHandle);

if not ErrorFlag then
begin
if (SerialNos <> FFileHeadList[CurFloppy - 1].SerialNo) and
(SerialNos <> -1) then
begin
tmpS := '备份数据 ' + IntToStr(CurFloppy) + ' 号盘序列号错误, ';
ErrorFlag := True;
end;
if not ErrorFlag then
begin
if CurFloppy <> FFileHeadList[CurFloppy - 1].CurFloppyNo then
begin
tmpS := '不是备份数据 ' + IntToStr(CurFloppy) + ' 号盘, ';
ErrorFlag := True;
end
else
begin
// 读取备份包文件个数,并赋给 FFileHeadList 个数
FloppyCount := FFileHeadList[CurFloppy - 1].FloppyCount;
if CurFloppy = 1 then // 只赋值一次即可
SetLength(FFileHeadList, FloppyCount);
if SerialNos = -1 then // 只赋值一次即可,作为全局参照
begin
SerialNos := FFileHeadList[CurFloppy - 1].SerialNo;
end;
end;
end;
end;
end
else
begin
tmpS := '没有发现备份数据 ' + IntToStr(CurFloppy) + ' 号盘, ';
ErrorFlag := True;
end;

if not ErrorFlag then
begin
if not CopyFile(PChar(SFile), PChar(fTempPath + ExtractFileName(SFile)), False) then
ErrorFlag := True;
end;

if ErrorFlag then
begin
if Application.MessageBox(PChar('拷贝失败: ' + tmpS + '重新拷贝吗?'),
'错误', MB_OKCANCEL + MB_ICONWARNING) = mrCancel then
begin
FErrorType := etCancel;
Break;
end
else
begin
ErrorFlag := False; // 仍对当前包进行循环操作
end;
end
else // 可进行下个包的拷贝
begin
Inc(CurFloppy);
if CurFloppy > FloppyCount then
begin
tmpS := '拷贝完毕';
Break;
end;
end;

end;
if ErrorFlag then
Result := False;
end;

function TADOBackup.Backup(SavePath: string): Boolean;
var
mADODataSet: TADODataSet;
i, InfoLen, TotalCount: integer;
TableStrings: TStrings;
BackUpStream: TFileStream;
fn, InfoText: string;
begin
Result := False;
if StartWrong then
Exit;
if SavePath = '' then
begin
Application.MessageBox('路径无效,请检查!', '系统信息', 0 + mb_Iconinformation);
exit;
end;
FSavepath := SavePath;
if FSavepath[Length(FSavepath)] <> '/' then
FSavepath := FSavepath + '/';

if DirectoryExists(FTempPath) then
RemoveDir(FTempPath);
Forcedirectories(FTempPath); // 建立临时路径
Forcedirectories(FSavePath); // 建立备份路径

FSqlStrings.SaveToFile(FTempPath + fn_SQLFile); // 储存SQL脚本
TableStrings := GetTablename(FSqlStrings, rtTable); // 提取表名用以建立文件

mADODataSet := TADODataSet.Create(nil);
mADODataSet.Connection := FADOConnection;
TableMaps.Clear;
TotalCount := FSqLStrings.Count - 1;
try
for i := 0 to FSQLStrings.Count - 1 do
begin
mADODataSet.Close;
mADODataSet.CommandText := FSQLStrings;
mADODataSet.Open;
fn := GenerateTempName(FTempPath);
TableMaps.Add(fn);
mADODataSet.SaveToFile(FTempPath + fn, pfxml);
if TotalCount = 0 then
FRadio := 100
else
FRadio := (100 * i div TotalCount);
if Assigned(FRatioChanged) then
FRatioChanged(Self, fRadio);
end;
TableMaps.SaveToFile(FTempPath + fn_TableMap);
TableStrings.Clear;
TableStrings.Add(FTempPath + '*.*');

if UpperCase(Copy(FSavePath, 1, 1)) = 'A' then
begin
FIsSavetoA := True;
FWorkPath := FTempPath;
FIsDevide := True; // 如是A盘,自动分卷
end
else
begin
FIsSavetoA := False;
FWorkPath := FSavePath;
end;

//!!!!!!!!!!!!!!! ForigPath????????????????
if FIsDevide then
fn := FOrigPath + FBackUpFileName
else
fn := FSavePath + FBackUpFileName;
BackUpStream := TFileStream.Create(fn, fmCreate);
BackUpStream.Size := 0;
// 首先写入备份标志,表明本文件为备份文件
BackUpStream.Write(BackUpSign[1], length(BackUpSign));
InfoText := FInfo.Text;
InfoLen := Length(InfoText);
// 写入附加信息长度
BackUpStream.write(InfoLen, sizeof(Integer));
// 写入附加信息
BackUpStream.write(InfoText[1], InfoLen);
try
BackUpFile.BackupToStream(TableStrings, BackUpStream); // 将多文件压缩整理为单一文件
finally
BackUpStream.free;
end;
if FIsDevide then
begin
CopyDevide;
DeleteFile(fn);
end
finally
mADODataSet.free;
RemoveDir(FTempPath);
end;
Result := True;
end;

procedure TADOBackup.PreviewFile(Sender: TOpenPreviewDialog; FileName: string);
begin
if GetInfo(FileName) then
begin
Sender.PreviewText.Lines.Assign(FInfo);
Sender.PreviewText.Font.Color := clBlack;
Sender.Hint := '备份数据内容:';
end
else
begin
Sender.Hint := '文件格式错误';
Sender.PreviewText.Lines.Clear;
Sender.PreviewText.Lines.Add('无法识别的文件格式:' + #13#10 + ' 此文件不是备份文件');
Sender.PreviewText.Font.Color := clRed;
end;
end;

function TADOBackup.BrowseBackFile: string;
var
OpenDlg: TOpenPreviewDialog;
begin
OpenDlg := TOpenPreviewDialog.Create(self);
OpenDlg.Title := '指定需恢复的备份文件';
OpenDlg.Filter := '数据备份文件(*.*)|*.*';
OpenDlg.OnPreview := PreviewFile;
Result := '';
try
if OpenDlg.Execute then
Result := OpenDlg.FileName;
finally
OpenDlg.Free;
end;
end;

constructor TADOBackup.Create(AOwner: TComponent);
var
TempDir: array[0..255] of Char;
begin
inherited Create(AOwner);
PackSize := 1456000;
FBackupFileName := 'Save.dat';

GetTempPath(255, @TempDir);
FTempPath := StrPas(TempDir) + Extractfilename(FBackUpFileName) + '/';
FOrigPath := StrPas(TempDir) + 'TempBack/';
Forcedirectories(FOrigPath);
FIsSavetoA := False;
BackupFile := TBackupFile.Create(nil);
FSQLStrings := TStringList.Create;
FDelSQLStrings := TStringlist.Create;
FInfo := TStringlist.Create;
TableMaps := TStringlist.Create;
FIsDevide := True;
FAutoDel := True;
FPackSize := 1456000;
end;

destructor TADOBackup.Destroy;
begin
RemoveDir(FOrigPath);
BackupFile.free;
FDelSQLStrings.Free;
FSQLStrings.free;
FInfo.Free;
TableMaps.Free;
inherited Destroy;
end;

initialization
Randomize;
end.


***************************************************************************
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, Buttons, ExtCtrls, ADOBackUP, FileCtrl, Registry;

type
Tfrm_Data = class(TForm)
Bevel1: TBevel;
lbl_Caption: TLabel;
edt_Path: TEdit;
SpeedButton1: TSpeedButton;
ProgressBar: TProgressBar;
btnOK: TButton;
btnCancel: TButton;
ADOBackUP: TADOBackUP;
OpenDialog: TOpenDialog;
Panel_Hide: TPanel;
CheckDate: TCheckBox;
DT_st: TDateTimePicker;
Label1: TLabel;
DT_end: TDateTimePicker;
Label2: TLabel;
Edt_FileName: TEdit;
procedure btnCancelClick(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
procedure btnOKClick(Sender: TObject);
procedure ADOBackUPProcession(Sender: TObject; Ratio: Integer);
procedure FormShow(Sender: TObject);
private
{ Private declarations }
FOK: Boolean;
public
{ Public declarations }
end;
function Show_Backup: Boolean;
function Show_Restore: Boolean;
implementation
uses DataModule;
{$R *.DFM}

function Show_Backup: Boolean;
begin
with Tfrm_data.Create(Application) do
begin
Caption := '数据备份';
lbl_Caption.Caption := '备份路径:';
DT_st.DateTime := Now;
DT_end.DateTime := DT_st.DateTime;
Edt_FileName.Text := FormatdateTime('yyyy-mm-dd', now) + '.dat';
FOK := False;
try
Showmodal;
finally
Result := FOK;
free;
end;
end;
end;

function Show_Restore: Boolean;
var
mHeight: Integer;
begin
with Tfrm_data.Create(Application) do
begin
Caption := '数据恢复';
mHeight := Panel_Hide.Height;
panel_Hide.Visible := False;
Bevel1.Height := Bevel1.Height - mHeight;
ProgressBar.Top := ProgressBar.Top - mHeight;
btnOK.Top := btnOK.Top - mHeight;
btnCancel.Top := btnCancel.Top - mHeight;
Height := Height - mHeight;
lbl_Caption.Caption := '备份文件:';
FOK := False;
try
Showmodal;
finally
Result := FOK;
free;
end;
end;
end;

procedure Tfrm_Data.btnCancelClick(Sender: TObject);
begin
Close;
end;

procedure Tfrm_Data.SpeedButton1Click(Sender: TObject);
var
mPath, mFile: string;
begin
if caption = '数据备份' then
begin
if Selectdirectory('请选择备份路径', 'C:', mPath) then
edt_Path.Text := mPath;
end
else if caption = '数据恢复' then
begin
mFile := ADOBackup.BrowseBackFile;
if mFile <> '' then
edt_Path.Text := mFile;
end;
end;

procedure Tfrm_Data.btnOKClick(Sender: TObject);
function mIsWrong: Boolean;
begin
edt_path.Text := trim(edt_Path.text);
Result := True;
if edt_Path.Text = '' then
begin
application.messagebox('请选择备份路径!', '系统提示', MB_ICONINFORMATION);
exit;
end;
try
ForceDirectories(edt_path.Text);
except
application.messagebox('创建路径不合法,请检查!', '系统提示', MB_ICONINFORMATION);
exit;
end;
Result := False;
end;
var
Reg: TRegistry;
mPath: string;
mTables, mSql: TStrings;
i: integer;
begin
FOK := True;
if caption = '数据备份' then
begin
mSql := TStringList.Create;
mTables := TStringlist.Create;
try
DM.ADOConn.GetTableNames(mTables); //得到表格
for i := mtables.Count - 1 downto 0 do
begin
if CheckDate.checked then //选择要备份的数据
begin
if mtables = '****' then
msql.Add('select * from ****
else
msql.Add('Select * from ' + mtables);
end
else //备份全部数据
msql.Add('Select * from ' + mtables);
end;
ADOBackUP.SQLStrings.Assign(mSql);
finally
msql.Free;
mtables.Free;
end;
mPath := edt_Path.Text;
if mPath[Length(mPath)] <> '/' then
mPath := mPath + '/';
Edt_fileName.Text := Trim(Edt_FileName.text);
if Edt_fileName.Text = '' then
ADOBackup.BackUpFileName := FormatdateTime('yyyy-mm-dd', now) + '.dat'
else
ADOBackup.BackUpFileName := Edt_FileName.Text;
ADOBackup.Info.Add('备份文件:' + ADOBackup.BackUpFileName);
ADOBackup.Info.Add('备份区段:');
if CheckDate.Checked then
begin
ADOBackup.Info.Add('* ' + FormatDateTime('dddddd', DT_st.DateTime) + ' 至');
ADOBackup.Info.Add(' ' + FormatDateTime('dddddd', DT_end.DateTime));
end
else
ADOBackup.Info.Add('* 全部区段');
if ADOBackUP.Backup(mPath) then
begin
Reg := TRegistry.Create;
try
Reg.RootKey := HKey_Local_Machine;
if Reg.OpenKey('/Software/Wolfsoft/Student/1.0', True) then
Reg.WriteString('BackupPath', mPath + ADOBackup.BackUpFileName);
finally
Reg.Free;
end;
application.messagebox('备份成功!', '系统提示', MB_ICONINFORMATION);
end
else
begin
FOK := False;
application.messagebox('备份失败!', '系统提示', MB_ICONINFORMATION);
end;
end
else if Caption = '数据恢复' then
begin
try
if ADOBackUP.Restore(edt_Path.text) then
application.messagebox('恢复成功!', '系统提示', MB_ICONINFORMATION)
else
begin
FOK := False;
application.messagebox('恢复失败!', '系统提示', MB_ICONINFORMATION);
end;
except
application.messagebox('恢复失败!', '系统提示', MB_ICONINFORMATION);
end;
end;
Self.Close;
end;

procedure Tfrm_Data.ADOBackUPProcession(Sender: TObject; Ratio: Integer);
begin
ProgressBar.Position := Ratio;
end;

procedure Tfrm_Data.FormShow(Sender: TObject);
var
Reg: TRegistry;
mFile: string;
begin
Reg := TRegistry.Create;
try
Reg.RootKey := HKey_Local_Machine;
if Reg.OpenKey('/Software/WolfSoft/Student/1.0', True) then
begin
mFile := Reg.ReadString('BackupPath');
if mFile <> '' then
begin
try
if Caption = '数据恢复' then
edt_path.text := mFile
else if Caption = '数据备份' then
edt_Path.Text := extractfilePath(mFile);
except
end;
end;
end;
finally
Reg.Free;
end;
end;

end.
 
好不容易把他的代码看完了,受益匪浅呀!!!谢谢!
 
多人接受答案了。
 
可以什么?
 
1.DELPHI中操作ACCESS数据库(建立.mdb文件,压缩数据库)
以下代码在WIN2K,D6,MDAC2.6下测试通过,
编译好的程序在WIN98第二版无ACCESS环境下运行成功.
//在之前uses ComObj,ActiveX
//声明连接字符串
Const
SConnectionString = 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s;'
+'Jet OLEDB:Database Password=%s;';

//=============================================================================
// Procedure: GetTempPathFileName
// Author : ysai
// Date : 2003-01-27
// Arguments: (None)
// Result : string
//=============================================================================
function GetTempPathFileName():string;
//取得临时文件名
var
SPath,SFile:array [0..254] of char;
begin
GetTempPath(254,SPath);
GetTempFileName(SPath,'~SM',0,SFile);
result:=SFile;
DeleteFile(result);
end;

//=============================================================================
// Procedure: CreateAccessFile
// Author : ysai
// Date : 2003-01-27
// Arguments: FileName:String;PassWord:string=''
// Result : boolean
//=============================================================================
function CreateAccessFile(FileName:String;PassWord:string=''):boolean;
//建立Access文件,如果文件存在则失败
var
STempFileName:string;
vCatalog:OleVariant;
begin
STempFileName:=GetTempPathFileName;
try
vCatalog:=CreateOleObject('ADOX.Catalog');
vCatalog.Create(format(SConnectionString,[STempFileName,PassWord]));
result:=CopyFile(PChar(STempFileName),PChar(FileName),True);
DeleteFile(STempFileName);
except
result:=false;
end;
end;

//=============================================================================
// Procedure: CompactDatabase
// Author : ysai
// Date : 2003-01-27
// Arguments: AFileName,APassWord:string
// Result : boolean
//=============================================================================
function CompactDatabase(AFileName,APassWord:string):boolean;
//压缩与修复数据库,覆盖源文件
var
STempFileName:string;
vJE:OleVariant;
begin
STempFileName:=GetTempPathFileName;
try
vJE:=CreateOleObject('JRO.JetEngine');
vJE.CompactDatabase(format(SConnectionString,[AFileName,APassWord]),
format(SConnectionString,[STempFileName,APassWord]));
result:=CopyFile(PChar(STempFileName),PChar(AFileName),false);
DeleteFile(STempFileName);
except
result:=false;
end;
end;

2.ACCESS中使用SQL语句应注意的地方及几点技巧
以下SQL语句在ACCESS XP的查询中测试通过
建表:
Create Table Tab1 (
ID Counter,
Name string,
Age integer,
[Date] DateTime);
技巧:
自增字段用 Counter 声明.
字段名为关键字的字段用方括号[]括起来,数字作为字段名也可行.

建立索引:
下面的语句在Tab1的Date列上建立可重复索引
Create Index iDate ON Tab1 ([Date]);
完成后ACCESS中字段Date索引属性显示为 - 有(有重复).
下面的语句在Tab1的Name列上建立不可重复索引
Create Unique Index iName ON Tab1 (Name);
完成后ACCESS中字段Name索引属性显示为 - 有(无重复).
下面的语句删除刚才建立的两个索引
Drop Index iDate ON Tab1;
Drop Index iName ON Tab1;

ACCESS与SQLSERVER中的UPDATE语句对比:
SQLSERVER中更新多表的UPDATE语句:
UPDATE Tab1
SET a.Name = b.Name
FROM Tab1 a,Tab2 b
WHERE a.ID = b.ID;
同样功能的SQL语句在ACCESS中应该是
UPDATE Tab1 a,Tab2 b
SET a.Name = b.Name
WHERE a.ID = b.ID;
即:ACCESS中的UPDATE语句没有FROM子句,所有引用的表都列在UPDATE关键字后.
上例中如果Tab2可以不是一个表,而是一个查询,例:
UPDATE Tab1 a,(Select ID,Name From Tab2) b
SET a.Name = b.Name
WHERE a.ID = b.ID;

访问多个不同的ACCESS数据库-在SQL中使用In子句:
Select a.*,b.* From Tab1 a,Tab2 b In 'db2.mdb' Where a.ID=b.ID;
上面的SQL语句查询出当前数据库中Tab1和db2.mdb(当前文件夹中)中Tab2以ID为关联的所有记录.
缺点-外部数据库不能带密码.

在ACCESS中访问其它ODBC数据源
下例在ACCESS中查询SQLSERVER中的数据
SELECT * FROM Tab1 IN [ODBC]
[ODBC;Driver=SQL Server;UID=sa;PWD=;Server=127.0.0.1;DataBase=Demo;]
外部数据源连接属性的完整参数是:
[ODBC;DRIVER=driver;SERVER=server;DATABASE=database;UID=user;PWD=password;]
其中的DRIVER=driver可以在注册表中的
HKEY_LOCAL_MACHINE/SOFTWARE/ODBC/ODBCINST.INI/
中找到

ACCESS支持子查询

ACCESS支持外连接,但不包括完整外部联接,如支持
LEFT JOIN 或 RIGHT JOIN
但不支持
FULL OUTER JOIN 或 FULL JOIN

ACCESS中的日期查询
注意:ACCESS中的日期时间分隔符是#而不是引号
Select * From Tab1 Where [Date]>#2002-1-1#;
在DELPHI中我这样用
SQL.Add(Format(
'Select * From Tab1 Where [Date]>#%s#;',
[DateToStr(Date)]));

ACCESS中的字符串可以用双引号分隔,但SQLSERVER不认,所以为了迁移方便和兼容,
建议用单引号作为字符串分隔符.

 
后退
顶部