2004. október 12., kedd

How to store and retrieve a text file in / from a resource


Problem/Question/Abstract:

I am trying to work out how to store approximately 1000 lines of text (3 columns, 30 chars each) inside an application. I do not want to have any .INI entries and would prefer not to use an external file.

Answer:

You can start with one and embed it into a resource. Let's assume you have the data in a normal textfile. Make a resource script file (filedata.rc) with a line like

FILEDATA RCDATA filedata.txt

Add this RC file to your Delphi 5 project group. This automatically gets you a $R line for it in the project DPR file and the resource is compiled for you when you build the project. Now, how to get at the data at runtime? Each line is a fixed length of 90 characters. So the file could be represented as an array of records of this type:

type
  TFileData = packed record
    col1, col2, col3: array[1..30] of Char;
    crlf: array[1..2] of Char;
  end;
  PFileData = ^TFileData;

Let's use a class to regulate access to the data. I assume you only need to read it, so there is no need to copy it from the resource.

type
  TDatahandler = class
  private
    FData: TList;
    FResHandle: THandle;
    function GetRecord(index: Integer): TFileData;
    procedure GetRecordCount: Integer;
    procedure InitDatalist;
  public
    constructor Create;
    destructor Destroy; override;
    property Records[index: Integer]: TFileData read GetRecord;
    property Recordcount: Integer read GetRecordcount;
  end;

implementation

constructor TDatahandler.Create;
begin
  inherited;
  FData := TList.Create;
  InitDatalist;
end;

destructor TDatahandler.Destroy;
begin
  Fdata.Free;
  if FResHandle <> 0 then
  begin
    UnlockResource(FResHandle);
    FreeResource(FResHandle);
  end;
  inherited;
end;

function TDatahandler.GetRecord(index: Integer): TFileData;
begin
  Result := PFileData(FData[i])^;
end;

procedure TDatahandler.GetRecordCount: Integer;
begin
  Result := FData.Count;
end;

procedure TDatahandler.InitDatalist;
var
  dHandle: THandle;
  pData: PFileData;
  numRecords, i: Integer;
begin
  pData := nil;
  dHandle := FindResource(hInstance, 'FILEDATA', RT_RCDATA);
  if dHandle <> 0 then
  begin
    numRecord := SizeofResource(hInstance, dHandle) div Sizeof(TFiledata);
    FResHandle := LoadResource(hInstance, dHandle);
    if FResHandle <> 0 then
    begin
      pData := LockResource(dHandle);
      if pData <> nil then
      begin
        FData.Capacity := NumRecords;
        for i := 1 to Numrecords do
        begin
          FData.Add(pData);
          Inc(pData);
        end;
      end
      else
        raise Exception.Create('Lock failed');
    end
    else
      raise Exception.Create('Load failed');
  end
  else
    raise Exception.Create('Resource not found');
end;

You can add a method to sort the FData list, for example, or a filter method that would populate another TList with pointer to records that match a set of criteria.

Nincsenek megjegyzések:

Megjegyzés küldése