在FreePascal中读取文件

5

我有一个具有特定结构的文本文件,即(对于每一行):字符、空格、字符、空格、双精度浮点数值、换行符。例如:

q w 1.23
e r 4.56
t y 7.89

什么是在Free Pascal中“提取”这些值的正确方法?
3个回答

6

FreePascal中的SysUtils有一个名为SScanF的函数(你可能在其他语言中知道它..)

我修改了RRUZ的示例以展示如何使用它。

uses SysUtils;

type
  TData=object
    Val1 ,
    Val2 : String;
    Val3 : Double;
  end;

procedure ProcessFile(aFileName:String);
var
  F     : Text;
  LData : TData;
  Line  : String;
begin
  DecimalSeparator:='.';
  AssignFile(F,aFileName);
  Reset(F);
  while not eof(F) do
  begin
    ReadLn(F,Line);
    SScanf(Line,'%s %s %f',[@LData.Val1,@LData.Val2,@LData.Val3]);

    //do something with the data
    WriteLn(LData.Val1);
    WriteLn(LData.Val2);
    WriteLn(LData.Val3);
  end;
end;

begin
  ProcessFile('C:\Bar\Foo\Data.txt');
  Writeln('Press Enter to exit');
  Readln;
end.

1
使用不安全的结构(例如,编译通过但如果字符串不是短字符串则会失败)。不建议这样做(无论是对于初学者还是专家)。 - Marco van de Voort
1
@MarcovandeVoort,您可以提供使用 SScanF 的正确方法吗? - SOUser

3
你可以使用 TStringList 类来加载文件,并使用 DelimitedText 属性将值拆分到另一个 TStringList 中,然后将这些值存储在记录中。
请查看此示例。
{$mode objfpc}{$H+}

uses
  Classes, SysUtils;

{$R *.res}

type
  TData=record
    Val1: Char;
    Val2: Char;
    Val3: Double;
  end;

procedure ProcessFile;
var
  LFile  : TStringList;
  Line   : TStringList;
  i      : Integer;
  LData  : TData;
  LFormat: TFormatSettings;
begin
  //set the propert format for the foat values
  LFormat:=DefaultFormatSettings;
  LFormat.DecimalSeparator:='.';

  LFile:=TStringList.Create;
  Line :=TStringList.Create;
  try
   //load the file
   LFile.LoadFromFile('C:\Bar\Foo\Data.txt');
   Line.Delimiter:=' ';
    for i:=0 to LFile.Count-1 do
    begin
      //read the line and split the result
      Line.DelimitedText:=LFile[i];
      //some basic check
      if Line.Count  <> 3 then raise Exception.Create('Wrong data length');

      //you can add additional check here    
      LData.Val1:=Line[0][3]; 
      LData.Val2:=Line[1][4];
      LData.Val3:=StrToFloat(Line[2],LFormat);

      //do something with the data
      WriteLn(LData.Val1);
      WriteLn(LData.Val2);
      WriteLn(LData.Val3);
    end;
  finally
    Line.Free;
    LFile.Free;
  end;
end;

begin
 try
    ProcessFile;
 except on E:Exception do Writeln(E.Classname, ':', E.Message);
 end;
 Writeln('Press Enter to exit');
 Readln;
end.

1
假设我们有兴趣读取一个文件,该文件由一个开关后的命令行参数提供,其中包含字符替换权重。
program WeightFileRead;
uses SysUtils, StrUtils;
var
   MyFile : TextFile;
   FirstChar, SecondChar, DummyChar : Char;
   Weight : Double;
begin
   if GetCmdLineArg ('editweights', StdSwitchChars) = ''
   then begin
      WriteLn ('Syntax: WeightFileRead -editweights filename'); exit
   end;
   AssignFile (MyFile, GetCmdLineArg ('editweights', StdSwitchChars));
   Reset (MyFile);
   try
      while not EOF (MyFile) do
      begin
         ReadLn (MyFile, FirstChar, DummyChar, SecondChar, Weight);
         WriteLn ('A: ', FirstChar, '; B: ', SecondChar, '; W: ', Weight:0:1);
      end
   finally
      CloseFile (MyFile)
   end
end.

在更一般的情况下,当前两个条目可以是较长的字符串时,我们可以使用ExtractWord来查找字符串中第n个以空格分隔的单词(或者使用ExtractSubstr将多个空格视为引入一个空单词),并将第三个转换为数字。
program WeightFileRead2;
uses SysUtils, StrUtils;
var
   MyFile : TextFile;
   FileLine : String;
begin
   if GetCmdLineArg ('editweights', StdSwitchChars) = ''
   then begin
      WriteLn ('Syntax: WeightFileRead -editweights filename'); exit
   end;
   AssignFile (MyFile, GetCmdLineArg ('editweights', StdSwitchChars));
   Reset (MyFile);
   try
      while not EOF (MyFile) do
      begin
         ReadLn (MyFile, FileLine);
         WriteLn ('A: ', ExtractWord (1, FileLine, [' ']),
                  '; B: ', ExtractWord (2, FileLine, [' ']),
                  '; W: ', StrToFloat (ExtractWord (3, FileLine, [' '])):0:1);
      end
   finally
      CloseFile (MyFile)
   end
end.

请注意,我使用[' ']而不是StdWordDelims,因为我不希望.或,成为单词分隔符。

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