它看起来像这样:
procedure dobackup;var LBackupAbortFlag: Boolean; LBackupStream: TStringStream;begin LBackupAbortFlag := False; LBackupStream := TStringStream.Create; try Execute('"C:\path to\gbak.exe" -b -t -v -user SYSDBA -pas "pw" <db> stdout',LBackupStream.WriteString,// Should process stdout (backup) SomeMemo.lines.Append,// Should process stderr (log) True,// Backup is "raw" False,// Log is not @LBackupAbortFlag); LBackupStream.Savetofile('C:\path to\output.fbk'); finally LBackupStream.Free; end;end;
问题是输出文件太小而无法包含实际备份.我仍然看到文件内容的元素.我尝试了不同的流类型,但这似乎没有什么区别.这可能会出错?
更新
需要明确的是:其他解决方案也是受欢迎的.最重要的是,我需要一些可靠的东西.这就是为什么我首先选择JEDI,而不是重新发明这样的事情.那么,如果它不会太复杂,那就太好了.
解决方法 当您希望合并stdout和stderr时,我的第一个答案是有效的.但是,如果您需要将这些分开,那么这种方法是没有用的.我现在可以通过仔细阅读您的问题和您的评论,看到您确实希望将两个输出流分开.现在,扩展我的第一个答案以涵盖这一点并非完全直截了当.问题是那里的代码使用阻塞I / O.如果你需要维修两个管道,那就有明显的冲突. windows中常用的解决方案是异步I / O,在windows世界中称为重叠I / O.但是,异步I / O的实现要比阻塞I / O复杂得多.
所以,我将提出一种仍然使用阻塞I / O的替代方法.如果我们想要服务多个管道,并且我们想要使用阻塞I / O,那么显而易见的结论是每个管道需要一个线程.这很容易实现 – 比异步选项容易得多.我们可以使用几乎相同的代码,但将阻塞读取循环移动到线程中.我的例子,以这种方式重新工作,现在看起来像这样:
{$APPTYPE CONSolE}uses SysUtils,Classes,windows;type TProcessOutputPipe = class private Frd: THandle; Fwr: THandle; public constructor Create; destructor Destroy; overrIDe; property rd: THandle read Frd; property wr: THandle read Fwr; procedure CloseWritePipe; end;constructor TProcessOutputPipe.Create;const PipeSecurityAttributes: TSecurityAttributes = ( nLength: SizeOf(TSecurityAttributes); binheritHandle: True );begin inherited; Win32Check(CreatePipe(Frd,Fwr,@PipeSecurityAttributes,0)); Win32Check(SetHandleinformation(Frd,HANDLE_FLAG_inherit,0));//don't inherit read handle of pipeend;destructor TProcessOutputPipe.Destroy;begin CloseHandle(Frd); if Fwr<>0 then CloseHandle(Fwr); inherited;end;procedure TProcessOutputPipe.CloseWritePipe;begin CloseHandle(Fwr); Fwr := 0;end;type TReadPipeThread = class(TThread) private FPipeHandle: THandle; FStream: TStream; protected procedure Execute; overrIDe; public constructor Create(PipeHandle: THandle; Stream: TStream); end;constructor TReadPipeThread.Create(PipeHandle: THandle; Stream: TStream);begin inherited Create(False); FPipeHandle := PipeHandle; FStream := Stream;end;procedure TReadPipeThread.Execute;var Buffer: array [0..4096-1] of Byte; BytesRead: DWORD;begin while Readfile(FPipeHandle,Buffer,SizeOf(Buffer),BytesRead,nil) and (BytesRead<>0) do begin FStream.WriteBuffer(Buffer,BytesRead); end;end;function ReadOutputFromExternalProcess(const Applicationname,Commandline: string; stdout,stderr: TStream): DWORD;var stdoutPipe,stderrPipe: TProcessOutputPipe; stdoutThread,stderrThread: TReadPipeThread; StartupInfo: TStartupInfo; ProcessInfo: TProcessinformation; lpApplicationname: PChar; ModfiableCommandline: string;begin if Applicationname='' then lpApplicationname := nil else lpApplicationname := PChar(Applicationname); ModfiableCommandline := Commandline; UniqueString(ModfiableCommandline); stdoutPipe := nil; stderrPipe := nil; stdoutThread := nil; stderrThread := nil; try stdoutPipe := TProcessOutputPipe.Create; stderrPipe := TProcessOutputPipe.Create; ZeroMemory(@StartupInfo,SizeOf(StartupInfo)); StartupInfo.cb := SizeOf(StartupInfo); StartupInfo.DWFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; StartupInfo.wShowWindow := SW_HIDE; StartupInfo.hStdOutput := stdoutPipe.wr; StartupInfo.hStdError := stderrPipe.wr; Win32Check(CreateProcess(lpApplicationname,PChar(ModfiableCommandline),nil,True,CREATE_NO_WINDOW or norMAL_PRIORITY_CLASS,StartupInfo,ProcessInfo)); stdoutPipe.CloseWritePipe;//so that the process is able to terminate stderrPipe.CloseWritePipe;//so that the process is able to terminate stdoutThread := TReadPipeThread.Create(stdoutPipe.rd,stdout); stderrThread := TReadPipeThread.Create(stderrPipe.rd,stderr); stdoutThread.WaitFor; stderrThread.WaitFor; Win32Check(WaitForSingleObject(ProcessInfo.hProcess,INFINITE)=WAIT_OBJECT_0); Win32Check(GetExitCodeProcess(ProcessInfo.hProcess,Result)); finally stderrThread.Free; stdoutThread.Free; stderrPipe.Free; stdoutPipe.Free; end;end;procedure Test;var stdout,stderr: TfileStream; ExitCode: DWORD;begin stdout := TfileStream.Create('C:\Desktop\stdout.txt',fmCreate); try stderr := TfileStream.Create('C:\Desktop\stderr.txt',fmCreate); try ExitCode := ReadOutputFromExternalProcess('','cmd /c dir /s C:\windows\system32',stdout,stderr); finally stderr.Free; end; finally stdout.Free; end;end;begin Test;end.
如果您希望添加对取消的支持,那么您只需在用户取消时添加对TerminateProcess的调用.这将使一切停止,函数将返回您提供给TerminateProcess的退出代码.我现在犹豫为你建议一个取消框架,但我认为这个答案中的代码现在非常接近满足你的要求.
总结以上是内存溢出为你收集整理的如何将二进制gbak输出重定向到Delphi流?全部内容,希望文章能够帮你解决如何将二进制gbak输出重定向到Delphi流?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)