我需要从命令行运行 sqlite 备份命令。我不想使用“cmd /c”。命令是:
sqlite3.exe MYDB.db .dump > MYDB.bak
我在 SO 上找不到任何示例来说明如何执行此操作。
到目前为止,我从各种 SO 帖子中收集的代码是这样的,但非常不完整:
function StartProcess(const ACommandLine: string; AShowWindow: boolean = True;
AWaitForFinish: boolean = False): Integer;
var
CommandLine: string;
StartupInfo: TStartupInfo;
ProcessInformation: TProcessInformation;
StdOutPipeRead, StdOutPipeWrite: THandle;
Handle: boolean;
begin
Result := 0;
FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
FillChar(ProcessInformation, SizeOf(TProcessInformation), 0);
StartupInfo.cb := SizeOf(TStartupInfo);
StartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
StartupInfo.hStdOutput := StdOutPipeWrite;
StartupInfo.hStdError := StdOutPipeWrite;
if not(AShowWindow) then
begin
StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow := SW_SHOWNORMAL;
end;
CommandLine := ACommandLine;
UniqueString(CommandLine);
Handle := CreateProcess(nil, PChar(CommandLine), nil, nil, False,
CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInformation);
CloseHandle(StdOutPipeWrite);
if Handle then
Result := ProcessInformation.dwProcessId;
if AWaitForFinish then
WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
CloseHandle(ProcessInformation.hProcess);
CloseHandle(ProcessInformation.hThread);
end;
由于 dump 命令的输出非常大,我不知道如何从 stdout 捕获输出然后重定向它。重定向到什么?复制骗局?还是到 TFileStream.Write?
我看过这篇文章,但在实现到输出文件的重定向方面它是不完整的。我想我应该问“实现这一点的最有效方法是什么?”
如果有人以前这样做过,请发布一个代码示例来说明我是如何做到的。
TIA。
编辑:
根据 David Heffernan 的回答,这是我修改后的代码,确实可以正常工作:
function StartProcessWithRedirectedOutput(const ACommandLine: string; const AOutputFile: string;
AShowWindow: boolean = True; AWaitForFinish: boolean = False): Integer;
var
CommandLine: string;
StartupInfo: TStartupInfo;
ProcessInformation: TProcessInformation;
StdOutFileHandle: THandle;
ProcessResult: boolean;
begin
Result := 0;
StdOutFileHandle := CreateFile(PChar(AOutputFile), GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0);
Win32Check(StdOutFileHandle <> INVALID_HANDLE_VALUE);
Win32Check(SetHandleInformation(StdOutFileHandle, HANDLE_FLAG_INHERIT, 1));
try
FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
FillChar(ProcessInformation, SizeOf(TProcessInformation), 0);
StartupInfo.cb := SizeOf(TStartupInfo);
StartupInfo.dwFlags := StartupInfo.dwFlags or STARTF_USESTDHANDLES;
StartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
StartupInfo.hStdOutput := StdOutFileHandle;
StartupInfo.hStdError := StdOutFileHandle;
if not(AShowWindow) then
begin
StartupInfo.dwFlags := StartupInfo.dwFlags or STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow := SW_HIDE;
end;
CommandLine := ACommandLine;
UniqueString(CommandLine);
ProcessResult := Win32Check(CreateProcess(nil, PChar(CommandLine), nil, nil, True,
CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInformation));
if ProcessResult then
begin
try
Result := ProcessInformation.dwProcessId;
if AWaitForFinish then
WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
finally
if ProcessInformation.hProcess <> INVALID_HANDLE_VALUE then
CloseHandle(ProcessInformation.hProcess);
if ProcessInformation.hThread <> INVALID_HANDLE_VALUE then
CloseHandle(ProcessInformation.hThread);
end;
end;
finally
CloseHandle(StdOutFileHandle);
end;
end;
procedure TfAdmin.DoDBBackup(ADBBackupFile: String);
var
b, p, q: String;
begin
b := ExtractFilePath(ParamStr(0)) + 'PPDB.bak';
p := ExtractFilePath(ParamStr(0)) + 'sqlite3.exe';
q := ExtractFilePath(ParamStr(0)) + 'PPDB.db .dump';
fMain.UniConnection1.Close;
try
StartProcessWithRedirectedOutput(p + ' ' + q, b, True, True);
finally
fMain.UniConnection1.Open;
end;
ZipMaster1.FSpecArgs.Add(b);
ZipMaster1.ZipFileName := ADBBackupFile;
ZipMaster1.Add;
DeleteFile(b);
ShowMessage('Backup complete!');
end;