【问题标题】:Console app output gets scrambled upon starting another console app using >> pipe redirection控制台应用程序输出在使用 >> 管道重定向启动另一个控制台应用程序时被打乱
【发布时间】:2019-03-25 14:07:26
【问题描述】:

我编写了一个很小的控制台应用程序,它使用文件的日期归档文件。具有相同日期的文件进入同一个存档。 我的应用程序使用此线程中描述的方法对每组文件调用 rar.exe 归档程序: How can I run a console application within my Delphi console application?

问题是,如果我使用标准 DOS 管道重定向字符“>”和“>>”将输出重定向到日志文件中,那么我的程序的 writelns 和 rar.exe 自己的文本输出会相互混合,不会遵循代码行规定的顺序。

如果我错过了管道重定向,则问题不存在。

因此,它看起来与操作系统 Windows 10 Pro 使用的磁盘写入策略有关。

    for i:=0 to DateList.Count-1 do begin
      Writeln('                                                                                                 ');
      Writeln(DateTimeToStr(Now()) + ' - ' + 'Creating archive file ' + IntToStr(i+1) + ' of ' + IntToStr(DateList.Count) + ' = ' + DateList[i] + '.rar');
      Writeln('                                                                                                 ');
      //Sleep(1000); // does not help
      // Writelns and RAR output gets scrambled
      s:=DateList[i];
      s1:='';//DateList[i] + EOL;
      for j:=0 to FileList.Count-1 do
        if pos(DateList[i],FileList[j])>0 then s1:=s1 + GetValuePart(FileList[j]) + EOL;
      try
        //s2:=ExtractFilePath(ParamStr(0)) + {'\' +} s + '.lst';
        s2:=ExtractFilePath(ParamStr(0)) + {'\' + s +} 'list.lst';
        ListFile:=TFileStream.Create(s2,fmCreate or fmShareDenyWrite);
        if ListFile.Write(PChar(s1)^,Length(s1))<>Length(s1) then ; // report list file write error
      finally
        ListFile.Free;
      end;
      s1:=IniFile.ReadString('Settings','RARPath',ExtractFilePath(ParamStr(0))) + 'rar.exe';
      s2:=IniFile.ReadString('Settings','ArchiveMode','a') + ' -ep "' +
          IniFile.ReadString('Settings','OperatingDir','') +
          IniFile.ReadString('Settings','ArchiveDir','') +
          s + '.rar" @"' + s2 + '"';

      s := s1 + ' ' + s2;
      //s := s + ' >> logfile.log'; // gets interpreted as RAR parameter
      UniqueString(s);
      try
        try
          //writeln('begin');
          FillChar(SI, sizeof(SI), 0);
          FillChar(PI, sizeof(PI), 0);
          SI.cb := sizeof(SI);

          if not CreateProcess(nil, PChar(s), nil, nil, true, 0, nil, nil, SI, PI) then
            Writeln('Cannot start RAR archiver ' + s);
            //RaiseLastOSError;

          WaitForSingleObject(PI.hProcess, INFINITE);

          CloseHandle(PI.hProcess);
          CloseHandle(PI.hThread);

          //writeln('end');
          inc(SuccessFiles);
        except
          on E: Exception do Writeln(E.ClassName, ': ', E.Message);
        end;
      finally
        //Readln;
      end;
      s2:='';
    end;

这里以日期/时间戳开头的行是程序自己的输出,其他行是 RAR 存档器输出。您可以看到两种类型的文本混合在一起。

2019. 03. 25. 14:03:15 - Starting file archiving operation 
2019. 03. 25. 14:03:15 - d:\Temp\testing\phx\
2019. 03. 25. 14:03:15 - 279 files found total
2019. 03. 25. 14:03:15 - 103 different dates found

2019. 03. 25. 14:03:15 - Creating archive file 1 of 103 = 2017. 04. 12..rar

RAR 4.11   Copyright (c) 1993-2012 Alexander Roshal   17 Feb 2012
Shareware version         Type RAR -? for help

Evaluation copy. Please register.

Updating archive d:\Temp\testing\phx\archived\2017. 04. 12..rar

Updating  d:\Temp\testing\phx\E00186000_PP20_0_KARAT.CSV                  23%  OK 
Updating  d:\Temp\testing\phx\E00186000_PP21_0_KARAT.CSV                 100%  OK 
Deleting d:\Temp\testing\phx\E00186000_PP21_0_KARAT.CSV    deleted
Deleting d:\Temp\testing\phx\E00186000_PP20_0_KARAT.CSV    deleted
Done

2019. 03. 25. 14:03:16 - Crea
RAR 4.11   Copyright (c) 1993-2012 Alexander Roshal   17 Feb 2012
Shareware version         Type RAR -? for help

Evaluation copy. Please register.

Updating archive d:\Temp\testing\phx\archived\2017. 05. 15..rar

Updating  d:\Temp\testing\phx\E00398000_PP64_0_KARAT.CSV                  31%  OK 
Updating  d:\Temp\testing\phx\E00398000_PP65_0_KARAT.CSV                  47%  OK 
Updating  d:\Temp\testing\phx\E00398000_PP69_0_KARAT.CSV                  73%  OK 
Updating  d:\Temp\testing\phx\E00398000_PP73_0_KARAT.CSV                  89%  OK 
Updating  d:\Temp\testing\phx\E00398000_PP83_0_KARAT.CSV                 100%  OK 
Deleting d:\Temp\testing\phx\E00398000_PP83_0_KARAT.CSV    deleted
Deleting d:\Temp\testing\phx\E00398000_PP73_0_KARAT.CSV    deleted
Deleting d:\Temp\testing\phx\E00398000_PP69_0_KARAT.CSV    deleted
Deleting d:\Temp\testing\phx\E00398000_PP65_0_KARAT.CSV    deleted
Deleting d:\Temp\testing\phx\E00398000_PP64_0_KARAT.CSV    deleted
Done
ting archive file 2 of 103 = 2017. 05. 15..rar

RAR 4.11   Copyright (c) 1993-2012 Alexander Roshal   17 Feb 2012
Shareware version         Type RAR -? for help

Evaluation copy. Please register.

Updating archive d:\Temp\testing\phx\archived\2017. 05. 16..rar

Updating  d:\Temp\testing\phx\E00398000_PP111_0_KARAT.CSV                 54%  OK 
Updating  d:\Temp\testing\phx\E00398000_PP114_0_KARAT.CSV                100%  OK 
Deleting d:\Temp\testing\phx\E00398000_PP114_0_KARAT.CSV    deleted
Deleting d:\Temp\testing\phx\E00398000_PP111_0_KARAT.CSV    deleted
Done

2019. 03. 25. 14:03:17 - Creating archive file 3 of 103 = 2017. 05. 16..rar

2019. 03. 25. 14:03:18 - Creating archive file 4 of 103 = 201
RAR 4.11   Copyright (c) 1993-2012 Alexander Roshal   17 Feb 2012
Shareware version         Type RAR -? for help

Evaluation copy. Please register.

Updating archive d:\Temp\testing\phx\archived\2017. 05. 18..rar

Updating  d:\Temp\testing\phx\E01125000_PP266_0_KARAT.CSV                 59%  OK 
Updating  d:\Temp\testing\phx\E01125000_PP275_0_KARAT.CSV                100%  OK 
Deleting d:\Temp\testing\phx\E01125000_PP275_0_KARAT.CSV    deleted
Deleting d:\Temp\testing\phx\E01125000_PP266_0_KARAT.CSV    deleted
Done
7. 05. 18..rar

感谢您提前提供任何帮助。

彼得 :-))

【问题讨论】:

  • 与其调用像 RAR.EXE 这样的外部进程,为什么不直接在自己的代码中使用嵌入式 RAR 库呢?
  • 因为这个解决方案实施起来更快
  • “快速”和“正确”经常发现自己处于光谱的相反两侧......
  • 尊敬的客户,我们公司工作速度快,价格便宜,质量上乘。您可以选择其中任何 2 个。谢谢你。 :D :P ;-)
  • 您不必将 write/writeln 与标准 output 全局一起使用,请查看文档以获取详细信息。也就是说,我猜您想将输出重定向到其他地方,因为您什么都没问,只是陈述了一些问题。

标签: delphi console pipe output


【解决方案1】:

下面的代码解决了这个问题。

    unit uDOSOutput;

    interface

    uses Windows;
    function ExecuteCommand(CommandLine:string):string;

    var
      mCommand: string;
      mOutputs: string;

    implementation

    function ExecuteCommand(CommandLine:string):string;
    var
      PROC:       TProcessInformation;
      Ret:        LongBool;
      START:      TStartupInfo;
      SA:         TSecurityAttributes;
      hReadPipe:  THandle;
      hWritePipe: THandle;
      dBytesRead: DWORD;
      sBuff:      array[0..255] of Char;
    begin
      if Length(CommandLine) > 0 then
        mCommand := CommandLine;
      if Length(mCommand) = 0 then
      begin
        MessageBox(0, PChar('Command Line empty.'), PChar('Error'), MB_ICONEXCLAMATION);
        Exit;
      end;
      SA.nLength := SizeOf(TSecurityAttributes);
      SA.bInheritHandle := TRUE;
      SA.lpSecurityDescriptor := nil;
      Ret := CreatePipe(hReadPipe, hWritePipe, @SA, 0);
      if not Ret then
      begin
        MessageBox(0, PChar('CreatePipe() failed.'), PChar('Error'), MB_ICONEXCLAMATION);
        Exit;
      end;
      FillChar(START ,Sizeof(TStartupInfo), #0);
      START.cb := SizeOf(TStartupInfo);
      START.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
      START.hStdOutput := hWritePipe;
      START.hStdError := hWritePipe;
      Ret := CreateProcess(nil, PChar(mCommand), @SA, @SA, TRUE, NORMAL_PRIORITY_CLASS, nil, nil, START, PROC);
      if Ret <> TRUE then
      begin
        MessageBox(0, PChar('File or command not found.'), PChar('Error'), MB_ICONEXCLAMATION);
        Exit;
      end;
      Ret := CloseHandle(hWritePipe);
      mOutputs := '';
      repeat
        Ret := ReadFile(hReadPipe, sBuff, 255, dBytesRead, nil);
        mOutputs := mOutputs + Copy(sBuff, 1, dBytesRead);
      until Ret = FALSE;
      Ret := CloseHandle(PROC.hProcess);
      Ret := CloseHandle(PROC.hThread);
      Ret := CloseHandle(hReadPipe);
      ExecuteCommand := mOutputs
    end;

    end.

原产地: http://www.delphibasics.info/home/delphibasicssnippets/capturetheoutputofadosapplication

【讨论】:

    【解决方案2】:

    根据您的问题,我不清楚您是否真的希望 RAR.EXE 的输出包含在您的日志文件中。如果您的日志中不需要它,那么我建议您像这样调用 RAR.EXE:

    C:\windows\system32\cmd.exe /c "[路径]\rar.exe" "[rar.exe 参数]"

    这应该会在第二个独立的控制台窗口中打开 RAR.EXE。

    【讨论】:

    • 不幸的是,这并不好,我的主要目标是捕获 rar.exe 日志。
    • @PeterBorosnyay 您可以将 rar.exe 的输出重定向到您在调用 CreateProcess() 时提供的管道,然后您可以从该管道中读取数据并将数据写入标准输出中。不会与您的其他输出重叠/干扰的方式。
    • 感谢 Remy,您的建议使我找到了正确的解决方案 :-))
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-30
    相关资源
    最近更新 更多