【问题标题】:Getting "ÿþI" as output data when reading from a .log file using delphi使用 delphi 从 .log 文件中读取时获取“ÿþI”作为输出数据
【发布时间】:2011-10-06 11:59:11
【问题描述】:

我正在尝试从 .log 文件中读取数据并处理其内容。日志文件由另一个应用程序创建。当我在 Delphi 中使用 readln 命令并在备忘录中显示文件内容时,我只能从包含超过 6000 行数据的文件中获取一行数据(ÿþI)。

    procedure TForm1.Button1Click(Sender: TObject);
    Var
        F : TextFile;
        s : string;
    begin
        AssignFile(F, 'data.log');
        Reset(F);

        while not Eof(F) do
        begin
            Readln(F, s);
            Memo1.Lines.Add(s);
        end;
    end;

有人知道问题出在哪里吗?

【问题讨论】:

  • 可能是编码错误。您应该检查文件的编码并调整您的程序以处理它(或转换文件,从长远来看更容易)。
  • 这不是万无一失的,但任何体面的文本编辑器,甚至一些不体面的文本编辑器(如记事本)都会尝试猜测编码。因此,如果数据在记事本中看起来不错,请单击 file-save-as 并查看它猜到了什么。无论如何,这是一个很好的初步猜测。

标签: delphi delphi-7 delphi-2007


【解决方案1】:

正如迈克尔所说,您正在处理一个 UTF-16 编码的文件,因此您必须手动加载和解码它。网上有各种基于WideStringTStringList 类类,或者Borland 在WideStrings 单元中有自己的实现,请尝试使用其中之一来代替Pascal 文件I/O,例如:

procedure TForm1.Button1Click(Sender: TObject);
var
  SL : TWideStringList;
  I: Integer;
  s : string;
begin
  SL := TWideStringList.Create;
  try
    SL.LoadFromFile('data.log');
    Memo1.Lines.BeginUpdate;
    try
      for I := 0 to SL.Count-1 do
        Memo1.Lines.Add(SL[I]);
    finally
      Memo1.Lines.EndUpdate;
    end;
  finally
    SL.Free;
  end;
end; 

或者:

uses
  .., WideStrings;

procedure TForm1.Button1Click(Sender: TObject);
var
  SL : TWideStringList;
begin
  SL := TWideStringList.Create;
  try
    SL.LoadFromFile('data.log');
    Memo1.Lines.Assign(SL);
  finally
    SL.Free;
  end;
end; 

或者,安装 TNTWare 或 TMS 的副本,它们都具有支持 Unicode 的组件。然后您应该能够将LoadFromFile() .log 文件直接输入您选择使用的 Unicode 备忘录组件。

【讨论】:

  • TNT Unicode Controls(“免费”版本)在这里托管tntunicodecontrols
  • 或使用标准 WideStrings.pas 中的 TWideStringList(至少从 D2006 开始包含)。但是它似乎无法处理 BOM
  • TWideStringList 以前没有在自己的独立单元中,这就是我之前没有提到它的原因。它曾经是另一个 Borland 互联网框架的一部分,可能安装也可能不安装。很高兴知道他们最终将其分离出来供大家使用。
【解决方案2】:

您正在处理一个 UTF-16 文件(如前两个字符所示),而 Delphi 2007 并没有为此做好准备,因此它在第一个 $0 字节处停止读取,因为 Readln 认为该行结束在那里。

您需要使用不同的方法来读取文件,并且您必须读取到 WideString(并可能将其转换为字符串)。由于 Delphi 2007 不支持 Unicode,我认为您还必须进行自己的行拆分,但我这里没有,所以我不完全确定。

【讨论】:

  • 一个粗略的技巧是:将全部内容读入 WideString。剥离 BOM。 Memo.Lines.Text := MyWideString.
【解决方案3】:

正如我在对 Remy 的回答的评论中提到的,在 WideStrings 中声明了一个 TWideStrings/TWideStringList:

uses WidesStrings;
//...
var
  Ws: TWideStrings;
  s: string;
  i: Integer;
begin
  Ws := TWideStringList.Create;
  try
    ws.LoadFromFile('C:\temp\UniTest.txt');
    for i := 0 to ws.Count - 1 do
    begin
      s := ws[i];
      Memo1.Lines.Add(s);
    end;
  finally
    ws.Free;
  end;
end;

但请注意,它不是TStrings 的后代,因此不能直接将其分配给 TMemo.Lines 之类的 TStrings 属性,您必须一一添加。

它似乎也无法处理 BOM(您的 ÿþ)或大端编码

【讨论】:

  • 实际上,来自WideStrings 单元的TWideStringList可以直接将Assign()ed 到任何TStrings 对象(反之亦然),如TWideStringList覆盖虚拟的 Assign()AssignTo() 方法来支持它。
  • @Remy:嗯,我分配Memo1.Lines := Ws; 的尝试失败了。我看到了 TWideString.Assign 句柄;e TStrings,但至少在 Delphi 2007 中没有看到其他方式。
  • TWideStringList 分配给TStrings 首先调用TStrings.Assign()TStrings.Assign() 无法识别 TWideStringList,因此 TPersistent.Assign() 调用 TWideStringList.AssignTo()next。至少在 D2010 中,TWideStringList.AssignTo() 可以识别 TStrings。也许 D2007 还不是这样。
猜你喜欢
  • 1970-01-01
  • 2014-05-08
  • 2020-04-04
  • 2020-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多