WriteConsoleW
似乎是一个非常神奇的功能。
procedure WriteLnToConsoleUsingWriteFile(CP: Cardinal; AEncoding: TEncoding; const S: string);
var
Buffer: TBytes;
NumWritten: Cardinal;
begin
Buffer := AEncoding.GetBytes(S);
// This is a side effect and should be avoided ...
SetConsoleOutputCP(CP);
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), Buffer[0], Length(Buffer), NumWritten, nil);
WriteLn;
end;
procedure WriteLnToConsoleUsingWriteConsole(const S: string);
var
NumWritten: Cardinal;
begin
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), PChar(S), Length(S), NumWritten, nil);
WriteLn;
end;
const
Text = 'АБВГДЕЖЅZЗИІКЛМНОПҀРСТȢѸФХѾЦЧШЩЪЫЬѢѤЮѦѪѨѬѠѺѮѰѲѴ';
begin
ReadLn; // Make sure Consolas font is selected
// Works, but changing the console CP is neccessary
WriteLnToConsoleUsingWriteFile(CP_UTF8, TEncoding.UTF8, Text);
// Doesn't work
WriteLnToConsoleUsingWriteFile(1200, TEncoding.Unicode, Text);
// This does and doesn't need the CP anymore
WriteLnToConsoleUsingWriteConsole(Text);
ReadLn;
end.
因此,在总结:
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), ...)
支持UTF-16。
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), ...)
不支持UTF-16。
我的猜测是,为了支持不同的ANSI编码,经典的Pascal I/O使用WriteFile
调用。
而且要记住,在文件,而不是控制台使用时必须工作,以及:
unicode text file output differs between XE2 and Delphi 2009?
这意味着,盲目使用WriteConsole
中断输出重定向。如果您使用WriteConsole
你应该回落到WriteFile
这样的:
var
NumWritten: Cardinal;
Bytes: TBytes;
begin
if not WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), PChar(S), Length(S),
NumWritten, nil) then
begin
Bytes := TEncoding.UTF8.GetBytes(S);
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), Bytes[0], Length(Bytes),
NumWritten, nil);
end;
WriteLn;
end;
注意与任何编码,它输出重定向在cmd.exe
工作正常。它只是将输出流写入文件不变。
但是,PowerShell希望在输出开始时包含ANSI输出或正确的前导码(/ BOM)到(或文件将被编码!)。另外,PowerShell将始终使用前导码将输出转换为UTF-16。
使用GetConsoleMode
,以找出是否标准手柄是一个控制台手柄MSDN recommends,也BOM中提到:如果它是一个标准的句柄是 重定向到一个文件中使用
WriteConsole失败。如果应用程序处理可重定向的多语言输出 ,请确定输出句柄是否为 控制台句柄(一种方法是调用GetConsoleMode函数, 检查它是否成功)。如果手柄是控制台手柄,请致电 WriteConsole。如果句柄不是控制台句柄,则重定向输出为 ,您应该调用WriteFile来执行I/O。请确保以 为Unicode纯文本文件加上字节顺序标记。有关更多 信息,请参阅使用字节顺序标记。
['可能重复](http://stackoverflow.com/q/265018/960757)?我认为['TOndrej的答案'](http://stackoverflow.com/a/268202/960757)涵盖了你的问题。 – TLama 2014-10-08 10:56:24
@TLama我看到了这个问题。我认为这是不同的。我想知道是否有办法使Writeln尊重Unicode。也许通过RTL函数调用开关行为。 – 2014-10-08 10:59:13
只是提示:http://www.bobswart.nl/Weblog/Blog.aspx?RootId=5:3011。另外:http://edn.embarcadero。com/article/39022 – 2014-10-08 11:28:18