best way to isolate record # in a flat file.

Ok folks. I'm writing a program that reads data from a datafile that is generated within the system. Since it's a standard delphi typed file handle, I am using filepos, filesize, and seek to move to record numbers. However, for some reason, my code keeps seeking me to record #0 or #1 or #2. I can never get to #2 or above. Here's an illustration of what I'm doing:

type datafilerecord = record
  deleted : boolean;
  first_name: string[30];
  last_name: string[30];
end;

In my function to move to the next record, I have this:

procedure TDvdCatForm.NextRecBtnClick(Sender: TObject);
var thefilepos : integer; // for debugging
begin
VerifySaveRec;
TheFilePos := filepos(moviefile); // for debugging
LoadRecord(filepos(moviefile)+1);
end;

The first time I press button named NextRecBtn, I get record #1 (ok), Next time I press the button, I could get #2 (ok) or I could get #1 again (WHAT!?)

Please don't tell me to use BDE or ODBC or anything. I have no experience in them and frankly I don't want to use them.

What am I doing wrong?

Thanks!
LVL 1
DanEgliAsked:
Who is Participating?
 
kretzschmarConnect With a Mentor Commented:
i've here a simple sample for a recordbased flatfile,
maybe you can adapt somewhat

unit r_file_u;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    BInsert: TButton;
    BUpdate: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    BPrev: TButton;
    BNext: TButton;
    BDelete: TButton;
    procedure FormCreate(Sender: TObject);
    procedure BInsertClick(Sender: TObject);
    procedure BUpdateClick(Sender: TObject);
    procedure BDeleteClick(Sender: TObject);
    procedure BNextClick(Sender: TObject);
    procedure BPrevClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

Type TheRec = Record  //a record
                Name1 : String[100];
                Name2 : String[100];
              end;
Var
  f : file of TheRec;    // file of this record  
  r : TheRec;   {Buffer} // a memorybuffer for this record
  cr : LongInt; {FileCursor}  //Points to the current record in the file
  rc : LongInt; {RecordCount} //Holds the amount of records in the file

implementation

{$R *.DFM}

//open the file
procedure TForm1.FormCreate(Sender: TObject);
begin
  assignfile(f,'MyFile.Dat');  //we will work with this file
  if not(fileexists('MyFile.Dat')) then  //if this file not exists
    rewrite(f)  //create this file
  else
    reset(f);   //open this file
  cr := 0;      //
  rc := fileSize(f);
end;

procedure TForm1.BInsertClick(Sender: TObject);
begin
  r.name1 := edit1.Text;
  r.name2 := edit2.Text;
  seek(f,rc);
  write(f,r);
  inc(rc);
  cr := rc;
end;

procedure TForm1.BUpdateClick(Sender: TObject);
begin
  if cr > 0 then
  begin
    r.name1 := edit1.text;
    r.name2 := edit2.text;
    seek(f,cr-1);
    write(f,r);
  end;
end;

procedure TForm1.BDeleteClick(Sender: TObject);
begin
  if rc > 0 then      {Are there record in}
  begin
    if cr <> rc then  {CurrentCursor is not LastRecord }
    begin
      seek(f,rc-1);   {Goto LastRecord}
      read(f,r);      {Buffer LastRecord}
      seek(f,cr-1);   {Goto Record to deleted}
      write(f,r);     {Paste over LastRecord}
    end
    else              {The Record to delete is LastRecord}
    begin
      if rc > 1 then    {More then one Record}
      begin
        seek(f,rc - 2); {Goto the Record before LastRecord}
        read(f,r);      {Read for Output}
        cr := rc - 1;   {set CurrentCursor to Record before LastRecord}
      end
      else
      begin             {Last Record will be deleted : File then empty }
        r.Name1 := '';
        r.Name2 := '';
        cr := 0;
      end;
    end;
    seek(f,rc-1);     {Goto LastRecord}
    truncate(f);      {Truncate the file here}
    edit1.text := r.name1;  {Output }
    edit2.text := r.Name2;
    dec(rc);
  end;
end;

procedure TForm1.BNextClick(Sender: TObject);
begin
  if cr < rc then
  begin
    read(f,r);
    inc(cr);
    edit1.text := r.name1;
    edit2.text := r.Name2;
  end;
end;

procedure TForm1.BPrevClick(Sender: TObject);
begin
  if cr > 1 then
  begin
    seek(f,cr-2);
    read(f,r);
    dec(cr);
    edit1.text := r.name1;
    edit2.text := r.Name2;
  end;

end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  closefile(f);
end;

end.

meikl ;-)
0
 
kretzschmarCommented:
you may seeking somewhere to another pos,
or you close and reopen your file somewhere
0
 
kretzschmarCommented:
maybe you should use a var for storing your current pos,
instead of seeking relative
0
Receive 1:1 tech help

Solve your biggest tech problems alongside global tech experts with 1:1 help.

 
rondiCommented:
Hi,

Please show the code for VerifySaveRec and LoadRecord

rondi.
0
 
wimmeyvaertCommented:
Is this flat file a line sequential file.
If so, then you could make a Schema-File (=recordlayout)
and use the file like a DB-Table (with the TTable-Comp).
You can then write Queries, Locate records, Move to records, Append Records, ... (Deletion of records is then not possible).

If you need a demo project, let me know.

Best regards,
The Mayor.
0
 
DanEgliAuthor Commented:
Ok. To answer the questions. It is not a line sequential. It is a file of records.

As far as storing current position in a var, thats fine, but I still need an efficent way to seek a particular record and then overwrite it.

Code for VerifySaveRec and LoadRecord:

procedure TDvdCatForm.VerifySaveRec;
begin
 if (itemunsaved) then
  if (Application.MessageBox('You have not saved this entry. Do you wish to save it now?', 'Exit Confirmation', MB_YESNO+MB_ICONQUESTION) = 6) then
    SaveScreenRecord;
end;


procedure TDvdCatForm.savescreenrecord;
begin
movie.deleted := dvdcatform.CheckBox1.Checked;
movie.Movie_ID := dvdcatform.MovieID.text;
movie.Title := dvdcatform.MovieName.Text;
movie.Format := dvdcatform.MovieFormat.ItemIndex;
movie.Genere := dvdcatform.MovieGenere.ItemIndex;
movie.Location := dvdcatform.MovieLocation.text;
if not filepos(moviefile) = filesize(moviefile) then
seek(moviefile, filepos(moviefile));
WRITE(moviefile, movie);
itemunsaved := false;
end;

procedure tDvdCatForm.loadrecord(recno: integer);
begin
  if (recno < 0) then
    begin
      ShowMessage('Cannot Move beyond top of file.');
      exit;
      end
    else if (recno > filesize(moviefile)-1) then
      begin
      ShowMessage('Cannot move beyond end of file.');
      exit;
    end;
  seek(moviefile, recno);
  read(moviefile, movie);
  dvdcatform.MovieID.text := movie.Movie_ID;
  dvdcatform.MovieName.text := movie.Title;
  dvdcatform.MovieFormat.ItemIndex := movie.Format;
  dvdcatform.MovieLocation.Text := movie.location;
  dvdcatform.MovieGenere.ItemIndex := movie.Genere;
  dvdcatform.OtherGenere.Text := movie.alt_genere;
  dvdcatform.CheckBox1.checked := movie.deleted;
  itemunsaved := false;
  if (length(movie.movie_id) < 6) then
  NewEntryMenuItemClick(Application);
end;
0
 
kretzschmarCommented:
your savescreenrecord do already overwrite the next record,
after the load the filecursor is behind the loaded record,
maybe you do duplicate/overwrite records unknown, which may cause the effect the rec#1 is near identical to rec#2

try this change(don't know if this applyable to your logic you use)

if not filepos(moviefile) = filesize(moviefile) then
//seek(moviefile, filepos(moviefile)); this may cause no seek
seek(moviefile, filepos(moviefile)-1);
WRITE(moviefile, movie);


i may also wroing in this case

meikl ;-)
0
 
DanEgliAuthor Commented:
Worth a shot. Thanks! I'll try it tonight.
0
All Courses

From novice to tech pro — start learning today.