Delphi 2010:如何模拟Delphi XE TStrings.Encoding属性?
Delphi XE在Delphi 2010:如何模拟Delphi XE TStrings.Encoding属性?,delphi,delphi-2010,Delphi,Delphi 2010,Delphi XE在tString类中添加了Encoding属性,该属性存储调用LoadFromFile()时从BOM中读取的编码 Delphi 2010没有此属性。 我想效仿它 我为TStrings创建了下面的类帮助程序。 助手可以工作,但要获取文件的BOM表,我找到的唯一解决方案是在文件流中重新加载相同的文件。我希望避免这种情况,因为TStrings.LoadFromFile()已经获得了BOM表 我如何告诉助手重新使用已找到的BOM表 unit TestEncodingName_00;
tString
类中添加了Encoding
属性,该属性存储调用LoadFromFile()
时从BOM中读取的编码
Delphi 2010没有此属性。
我想效仿它
我为TStrings
创建了下面的类帮助程序。
助手可以工作,但要获取文件的BOM表,我找到的唯一解决方案是在文件流中重新加载相同的文件。我希望避免这种情况,因为TStrings.LoadFromFile()
已经获得了BOM表
我如何告诉助手重新使用已找到的BOM表
unit TestEncodingName_00;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtDlgs;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMyStrings = class helper for TStrings // emulate TStrings.Encoding
private
function GetEncodingName(fPath:string):string;
public
property EncodingName[fPath:string]:string read GetEncodingName;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function TMyStrings.GetEncodingName(fPath:string):string;
var
fLen : integer;
fBuffer : TBytes;
fEncoding : TEncoding;
fName : string;
fFs : TFileStream;
begin
fFs := TFileStream.Create(fPath, fmOpenRead);
try
SetLength(fBuffer, 4);
flen := fFs.Read(fBuffer[0], 4);
if flen < 4 then
SetLength(fBuffer, flen);
fEncoding := nil;
TEncoding.GetBufferEncoding(fBuffer, fEncoding);
if fEncoding = TEncoding.Unicode then
fName := 'Unicode'
else if fEncoding = TEncoding.UTF8 then
fName := 'UTF8'
else fName := 'Default';
finally
fFs.Free;
end;
result := fName;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
EncName : string;
begin
(* sample UTF8.txt
Ā ā Ă ă
Ρ Σ Τ Υ
ぁ あ ぃ
*)
Memo1.Lines.LoadFromFile('Sample UTF8.txt');
//from here TStrings knows the BOM but I don't know
// how to refer to it...
// so I have to create again a stream of the same file to
// get the BOM. I don't like that.
EncName := Memo1.Lines.EncodingName['Sample UTF8.txt'];
Memo1.Lines.Add(#13#10'Encoding : ' + EncName);
end;
end.
单元测试编码名称\u 00;
接口
使用
窗口、消息、系统工具、变体、类、图形、控件、窗体、,
对话框、stdctrl、extdlg;
类型
TForm1=类(TForm)
备忘录1:TMemo;
过程表单创建(发送方:ToObject);
私有的
{私有声明}
公众的
{公开声明}
结束;
TMyStrings=TStrings的类助手//模拟TStrings.Encoding
私有的
函数GetEncodingName(fPath:string):string;
公众的
属性EncodingName[fPath:string]:字符串读取GetEncodingName;
结束;
变量
表1:TForm1;
实施
{$R*.dfm}
函数tmystings.GetEncodingName(fPath:string):string;
变量
fLen:整数;
fBuffer:t字节;
编码:十位编码;
fName:字符串;
fFs:TFileStream;
开始
fFs:=TFileStream.Create(fPath,fmOpenRead);
尝试
设定长度(fBuffer,4);
flen:=fFs.Read(fBuffer[0],4);
如果flen<4,则
设定长度(fBuffer,flen);
编码:=零;
GetBufferEncoding(fBuffer,fEncoding);
如果fEncoding=TEncoding.Unicode,则
fName:=“Unicode”
否则,如果fEncoding=TEncoding.UTF8,则
fName:=“UTF8”
else fName:=“默认值”;
最后
免费的;
结束;
结果:=fName;
结束;
过程TForm1.FormCreate(发送方:TObject);
变量
名称:字符串;
开始
(*示例UTF8.txt
Ā ā Ă ă
Ρ Σ Τ Υ
ぁ あ ぃ
*)
Memo1.Lines.LoadFromFile('Sample UTF8.txt');
//从这里TStrings知道BOM但我不知道
//如何参考它。。。
//因此,我必须再次创建一个相同文件的流,以
//获取BOM表。我不喜欢那样。
EncName:=Memo1.Lines.EncodingName['Sample UTF8.txt'];
备忘录1.行。添加(#13#10'编码:'+EncName);
结束;
结束。
首先,发现BOM编码的是LoadFromStream()
,而不是LoadFromFile()
LoadFromFile()
只需将文件打开到TFileStream
中,然后调用loadfromfstream()
在Delphi(2009和)2010中,发现的BOM编码不会存储在您可以访问的任何位置。这正是XE通过添加新的Encoding
属性所解决的问题。在解析之前将文件数据解码为Unicode destring时,编码仅用作LoadFromStream()
内部的局部变量,然后在退出LoadFromStream()
时将其丢弃。你无法改变这种行为
因此,唯一的解决方案是手动加载文件,以便可以发现其BOM表。理想情况下,可以在子类中重写LoadFromStream()
,但不能使TMemo.line
使用自定义类。类助手也不能覆盖虚拟方法
但是,您可以从TStringList
派生自定义类来重写LoadFromStream()
,自己加载文件,然后Assign()
将TStringList
分配到TMemo.line
。例如:
unit TestEncodingName_00;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtDlgs;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMyStringList = class(TStringList)
private
fEncoding: TEncoding;
public
{ The single-parameter LoadFromStream(Stream: TStream) simply
calls LoadFromStream(Stream: TStream; Encoding: TEncoding) with
the Encoding parameter set to nil, so you only have to override
that version of LoadFromStream()... }
procedure LoadFromStream(Stream: TStream; Encoding: TEncoding); override;
property Encoding: TEncoding read fEncoding;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TMyStringList.LoadFromStream(Stream: TStream; Encoding: TEncoding);
var
Size: Integer;
Buffer: TBytes;
begin
{ this is similar to the implementation that LoadFromStream()
uses in XE+, but with some differences:
1. the Encoding property is assigned a bit differently, as XE+
utilizes a TEncoding.Clone() method when the specified Encoding
is not a standard RTL encoding (ie, is a custom user class), but
Clone() does not exist in D2009/2010.
2. XE+ has a TStrings.DefaultEncoding property, which is passed
to TEncoding.GetBufferEncoding() as the default to return if no
BOM is detected, but that property and parameter do not exist in
D2009/2010.
3. TStrings.LoadFromStream() does not check if Size is 0 (file is empty)
before dereferencing the Buffer that is passed to Stream.Read().
That is a runtime crash waiting to happen! }
BeginUpdate;
try
Size := Stream.Size - Stream.Position;
SetLength(Buffer, Size);
if Size > 0 then
Stream.Read(Buffer[0], Size);
Size := TEncoding.GetBufferEncoding(Buffer, Encoding);
fEncoding := Encoding;
SetTextStr(Encoding.GetString(Buffer, Size, Length(Buffer) - Size));
finally
EndUpdate;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
EncName : string;
List: TMyStringList;
begin
List := TMyStringList.Create;
try
List.LoadFromFile('Sample UTF8.txt');
if List.Encoding = TEncoding.Unicode then
EncName := 'Unicode'
else if List.Encoding = TEncoding.UTF8 then
EncName := 'UTF8'
else
EncName := 'Default';
Memo1.Lines.Assign(List);
Memo1.Lines.Add;
Memo1.Lines.Add('Encoding : ' + EncName);
finally
List.Free;
end;
end;
end.
非常感谢你的精彩回答,感谢你编辑我的帖子:-)当我再次阅读你的答案时,我不记得我写了一篇如此好的英语!