6

如何从 Delphi 控制台应用程序写入标准输出?

这是我尝试过的。我根据我能找到的信息操纵了这个简单的测试应用程序,从磁盘读取文件并将其输出到控制台标准输出:

program ConsoleOut;
{$APPTYPE CONSOLE}
uses
  Classes, Windows, SysUtils;

var
  S: TMemoryStream;
  OutputStream: THandleStream;
  ss: string;
  Buffer: PByte;
  i: Integer;
begin
  S := TMemoryStream.Create;
  S.LoadFromFile('1.jpg');
  S.Seek(0, soFromBeginning);

  //Am I right that from now on writing to OutputStream will write to stdout?
  OutputStream := THandleStream.Create(GetStdHandle(STD_OUTPUT_HANDLE));

  GetMem(Buffer, S.Size);
    S.ReadBuffer(Buffer^, S.Size);
    i := OutputStream.Write(Buffer^, S.Size); //i = 0 here for some reason
  FreeMem(Buffer, S.Size);

  Writeln(i, ' byte written to output');
  Readln(ss); //Don't exit app to read previous line
  S.Free;
end.

但由于某种原因它失败了。您能否指导我以正确的方式写入标准输出?

4

1 回答 1

7

你的方法是合理的。但是,如果标准输出连接到控制台,那么您的代码将失败。GetLastError跟踪流写入的调用会显示错误代码ERROR_NOT_ENOUGH_MEMORY

没有足够的存储空间来处理此命令。

如果您将标准输出重定向到文件,那么您的代码将正常工作。当然,您并不想将二进制数据发送到控制台。这只会将不可读的内容放在控制台上,并使计算机发出恼人的哔哔声!

如果您必须输出到控制台,那么您需要找出控制台设备缓冲区的大小并以适当大小的块写入它。我必须承认,我不确定你是怎么做到的。你可以使用试错法,但这对我没有吸引力。想必有办法查询控制台来查找信息。

查看文档WriteConsole,似乎 64K 是上限。事实上,如果我将空格写入您的句柄流,那么我可以一次写入近 64K。但是,如果我写原始的 JPEG 二进制数据,那么它会更早地给出。所以我认为这也是问题的一部分——不要将 JPEG 文件转储到控制台上。

另一条评论。由于您将文件的内容读入内存流,因此无需分配中间缓冲区。可以S.Memory^直接写。

于 2013-03-21T08:08:15.790 回答