使用Delphi读取.log文件时,输出数据为"ÿþI"是什么原因?

6

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

    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;

有人知道问题可能是什么吗?


2
可能是编码错误。您应该检查文件使用的编码,并调整程序以处理它(或者在长期运行中进行转换)。 - Fred Foo
它并不是百分之百可靠的,但任何一个像样的文本编辑器,甚至一些不像样的(比如记事本)都会尝试猜测编码。因此,如果数据在记事本中看起来正常,请单击“文件-另存为”并查看它猜测的内容。无论如何,这是一个很好的初始猜测。 - Warren P
3个回答

4

正如Michael所说,你正在处理一个UTF-16编码的文件,因此你将需要手动加载和解码它。网上有各种基于WideString的类似TStringList的类,或者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的组件。然后你就可以直接使用任何你选择使用的Unicode Memo组件加载.log文件。


TNT Unicode Controls(“免费”版本)托管在此处tntunicodecontrols - LU RD
或者使用标准的WideStrings.pas中包含的TWideStringList(至少从D2006开始)。但是它似乎不能处理BOM。 - Gerry Coll
TWideStringList 以前不是独立的单元,这就是为什么我之前没有提到它的原因。它曾经是 Borland 的另一个互联网框架的一部分,可能已安装或未安装。很高兴知道他们最终将其分离出来供普遍使用。 - Remy Lebeau

4
您正在处理一个UTF-16文件(正如前两个字符所示),而Delphi 2007没有准备好处理它,因此它会在第一个$0字节处停止读取,因为Readln认为该行在那里结束。
您需要使用不同的方法来读取文件,并且需要读入一个WideString(并可能将其转换为字符串)。由于Delphi 2007不完全支持Unicode,我认为您还需要自己进行行拆分,但我在这里无法提供更确切的信息。

一个粗糙的hack是:将整个内容读入WideString中。去掉BOM。Memo.Lines.Text := MyWideString - David Heffernan

0
正如在我的评论中提到的,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 的子类,因此不能直接分配给 TStrings 属性,如 TMemo.Lines,您必须逐个添加。
它似乎也无法处理 BOM(即您的 ÿþ)或大端编码。

实际上,来自WideStrings单元的TWideStringList可以直接分配(Assign())给任何TStrings对象(反之亦然),因为TWideStringList重写了虚拟的Assign()AssignTo()方法以支持这一点。 - Remy Lebeau
@Remy:嗯,我的尝试将Memo1.Lines := Ws;赋值失败了。我发现在Delphi 2007中,TWideString.Assign处理TStrings,但反过来不行。 - Gerry Coll
TWideStringList分配给TStrings会首先调用TStrings.Assign()TStrings.Assign()不识别TWideStringList,因此TPersistent.Assign()接下来调用TWideStringList.AssignTo()。至少在D2010中,TWideStringList.AssignTo()能够识别TStrings。也许在D2007中还没有这种情况。 - Remy Lebeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接