Delphi 独立于平台的检查Writeln-to-Output是否可以安全使用的方法?
对于具有OSX和Android支持的较新的Delphi版本,是否有独立于平台的方法来检测to是否可以安全使用 输出文档包含一个注释 大多数进程没有标准的输出文件,并且无法写入 输出引发错误。如果需要,Delphi程序有一个标准输出文件 它们作为控制台应用程序链接 我的主要目标是为日志记录提供独立于平台的回退,但要避免在不存在控制台(stdout)时可能出现的任何操作系统错误 例如:这样检查是否足够:Delphi 独立于平台的检查Writeln-to-Output是否可以安全使用的方法?,delphi,console,freepascal,Delphi,Console,Freepascal,对于具有OSX和Android支持的较新的Delphi版本,是否有独立于平台的方法来检测to是否可以安全使用 输出文档包含一个注释 大多数进程没有标准的输出文件,并且无法写入 输出引发错误。如果需要,Delphi程序有一个标准输出文件 它们作为控制台应用程序链接 我的主要目标是为日志记录提供独立于平台的回退,但要避免在不存在控制台(stdout)时可能出现的任何操作系统错误 例如:这样检查是否足够: 因此,问题可以重新表述为:“如果是真的,Delphi应用程序是否总是安全地使用?” 因为它是一
因此,问题可以重新表述为:“如果是真的,Delphi应用程序是否总是安全地使用?” 因为它是一种回退日志方法,所以如果日志消息是“不可见的”(重定向到/dev/null),那么对我来说就可以了,只要代码能够保证跨平台运行而不会出错
如果是,此代码是否也可以安全地使用免费Pascal?(请参阅)我将使用异常机制 大概是这样的:
type
trilean = (dunno, yes, no);
TLogger = class(TSomething)
private
class var FConsoleIsSafe: trilean;
function GetConsoleIsSafe: boolean;
public
property ConsoleIsSafe: boolean read GetConsoleIsSafe;
....
implementation
function TLogger.GetConsoleIsSafe: boolean;
begin
if (FConsoleIsSafe = dunno) then try
WriteLn('test');
FConsoleIsSafe:= yes;
except
FConsoleIsSafe:= no;
end;
Result:= (FConsoleIsSafe = yes);
end;
不是最终答案,但将{$IFDEF}依赖于平台的调用写入基于平台的Independent POSIX
int fileno(文件*流)
..此函数返回与流关联的文件描述符。如果检测到错误(例如,如果流无效)或流未对文件进行I/O,则fileno返回-1
在unistd.h中还为属于标准流stdin、stdout和stderr的文件描述符定义了符号常量
标准文件号。。此宏的值为1,这是标准输出的文件描述符
标准文件号。。此宏的值为2,这是标准错误输出的文件描述符
因此,如果与控制台输出相对应的流的fileno
的平台独立请求返回2或1,则不会重定向,如果返回-1,则输出没有结束
Delphi和Free Pascal、Virtual Pascal和GNU Pascal的确切代码可能会有所不同。
去看看你感兴趣的目标平台的运行库,例如
系统.pas之后,我想出了这个解决方案:
function CanWriteln: Boolean;
begin
{$IFOPT I+}
{$DEFINE IOCHECK_ON}
{$I-}
{$ENDIF}
if TTextRec(Output).Mode <> fmClosed then
Result := True
else
begin
Rewrite(Output);
Result := IOResult = 0;
end;
{$IFDEF IOCHECK_ON}
{$I+}
{$ENDIF}
end;
函数CanWriteln:Boolean;
开始
{$IFOPT I+}
{$DEFINE IOCHECK_ON}
{$I-}
{$ENDIF}
如果TTextRec(输出).fm模式关闭,则
结果:=真
其他的
开始
重写(输出);
结果:=IOResult=0;
结束;
{$IFDEF IOCHECK_ON}
{$I+}
{$ENDIF}
结束;
仅在具有不同设置的Windows上测试({$APPTYPE CONSOLE},“生成控制台应用程序”设置,AllocConsole),但在所有情况下,它都工作正常。IsConsole将为连接到控制台的GUI应用程序返回false。也许你需要一个额外的间接层。允许您的代码客户端提供一个输出设备,您的代码将写入该设备。我认为为Android编写支持控制台的应用程序没有任何意义。日志应该通过写入日志文件而不是stdout来完成。我还想知道代码是否只会被编译到您控制的程序中。因为如果是库代码,那么如果库代码开始在标准输出上写入,库的使用者可能会感到不安。为什么不使用异常机制呢?你只需要打一次电话,这样就不会有速度问题。这是破坏性的。它导致输出显示在控制台上。人们可能更喜欢没有副作用的测试。Write(“”)
这样就没有副作用了?Write(“”)
不会触发任何IO错误,因为没有什么可做的。更糟糕的是,它可能会调用具有任意句柄作为参数的系统函数。由此造成的麻烦可能无法挽回。经验法则:如果某个东西可能导致访问冲突或类似的“损坏”系统错误,则不要尝试恢复,而是恢复到故障保护并中止。在Windows上,我认为您应该调用GetStdHandle来测试是否连接了输出设备。在Unix平台上,您可以调用等效的API。我认为问题是关于一种独立于平台的方式。要做到这一点,需要使用特定于平台的代码,那会是什么?我写的函数没有任何依赖于平台的代码。我可能弄错了。我只认为getmem返回初始化内存是有文档记录的。Afaik只初始化自动全局变量。如果您知道它在文档中的位置,请毫不犹豫地提及它。总是很难区分Delphi语言和Delphi语言实现。Fileno假定以libc为中心的I/O(文件*)。免费的Pascal基于基于句柄的系统函数实现自己的、Pascal编写的I/O。与此等效的是Getfilehandle(),但它仅从textrec/filerec返回句柄,因此在某种程度上减少了Stefan的解决方案,具有相同的限制(假设标准描述符在不使用时初始化)。
function CanWriteln: Boolean;
begin
{$IFOPT I+}
{$DEFINE IOCHECK_ON}
{$I-}
{$ENDIF}
if TTextRec(Output).Mode <> fmClosed then
Result := True
else
begin
Rewrite(Output);
Result := IOResult = 0;
end;
{$IFDEF IOCHECK_ON}
{$I+}
{$ENDIF}
end;