6

从 D2007 转换到 XE2,我转换了这个函数

function Add_Line( FileStream : TFileStream; ALine : string) : boolean;

function Add_Line( FileStream : TFileStream; ALine : string; Enc: TEncoding = nil) : boolean;
var
  AStr: ANSISTring;
begin
  Result := True;
  if Enc = nil then Enc := TEncoding.ANSI;
  try
//Old    FileStream.WriteBuffer( Pointer(ALine)^, Length(ALine) );
    if Enc = TEncoding.UTF8 then
      AStr := UTF8Encode(ALine)
    else
      AStr := ANSIString(ALine);
    FileStream.WriteBuffer( AStr[1], Length(ALine) );
    end;
  except
    Result := False;
  end;
end;

理由:

  • 尽可能少地使用 Add_Line 更改代码

  • 接受自动更改为 Unicode,仅在最后一刻写入 8 位文本文件(用于 XML 和 CSV)。如果我们愿意,将来我们仍然可以迁移到 UTF-16 文件。

我本来想定义类似的东西:

function Add_Line( FileStream : TFileStream; ALine : string; Enc: TEncoding = TEncoding.ANSI) : boolean;

但编译器抱怨;-)

这样的事情可能吗?

4

2 回答 2

12

默认参数必须是编译时常量,但如果你需要更高级的东西,你可以创建重载:

function Add_Line( FileStream : TFileStream; ALine : string) : boolean; overload;
function Add_Line( FileStream : TFileStream; ALine : string; Enc: TEncoding) : boolean; overload;


function Add_Line( FileStream : TFileStream; ALine : string) : boolean;
begin
  Result := Add_Line(FileStream, ALine, TEncoding.ANSI);
end;

您甚至可以添加inline关键字以获得与默认参数所产生的完全相同的生成代码,如果它有效的话。

注意:您似乎不支持除TEncoding.ANSIand以外的任何内容TEncoding.UTF8。在这种情况下,TEncoding参数似乎有点过头了,您可以改用UTF8: Boolean参数(或重新编写代码以使用任意编码CodePage)。

注2:FileStream.WriteBuffer( AStr[1], Length(ALine) );是错误的,因为Length(ALine)Length(AStr)不必相同,应该Length(AStr)改用。此外,当为空字符串AStr[1]时可能会导致异常,您可以添加一个特殊情况以仅在不为空时调用。AStrWriteBufferAStr

于 2012-09-10T12:59:38.860 回答
6

其他人评论了如何为TEncoding参数指定默认值。我想指出,您的使用TEncoding通常是完全错误的。

TEncoding.UTF8不是获得 UTF-8 编码对象的唯一方法(TEncoding.GetEncoding(65001)是另一种方法),因此TEncoding.UTF8专门检查是错误的做法。更糟糕的是,您完全忽略了任何非 UTF8 编码,而只是将其他所有内容编码为 plain AnsiString,这完全违背了使用的全部目的TEncoding。例如,用户可以传入 ISO-8859-X 编码对象,您的输出不会像用户请求的那样进行 ISO 编码。您也可以将参数更改为UseUTF8: Boolean = False参数,因为这就是您有效使用它的方式:

function Add_Line( FileStream : TFileStream; ALine : string; UseUTF8: Boolean = False) : boolean;  
var  
  AStr: AnsiString;  
begin  
  Result := True;  
  try  
    if UseUTF8 then  
      AStr := UTF8Encode(ALine)  
    else  
      AStr := AnsiString(ALine);  
    if AStr <> '' then
      FileStream.WriteBuffer( AStr[1], Length(AStr) );  
  except  
    Result := False;  
  end;  
end;  

正确的使用方法TEncoding是让它做实际的编码,不要自己编码:

function Add_Line( FileStream : TFileStream; ALine : string; Enc: TEncoding = nil) : boolean; 
var 
  AStr: TBytes; 
begin 
  if ALine = '' then
  begin
    Result := True;
    Exit;
  end; 
  Result := False;
  try 
    if Enc = nil then Enc := TEncoding.Ansi; 
    AStr := Enc.GetBytes(ALine); 
    // GetBytes() returns 0 bytes if it fails to encode, it does not raise an exception!
    if Length(AStr) = 0 then Exit;
    FileStream.WriteBuffer( AStr[0], Length(AStr) )
  except 
    Exit;
  end; 
  Result := True;
end; 
于 2012-09-10T21:23:38.367 回答