Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 2010:如何模拟Delphi XE TStrings.Encoding属性?_Delphi_Delphi 2010 - Fatal编程技术网

Delphi 2010:如何模拟Delphi XE TStrings.Encoding属性?

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;

Delphi XE在
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. 

非常感谢你的精彩回答,感谢你编辑我的帖子:-)当我再次阅读你的答案时,我不记得我写了一篇如此好的英语!