Solved

best way to isolate record # in a flat file.

Posted on 2001-08-21
8
139 Views
Last Modified: 2010-04-06
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!
0
Comment
Question by:DanEgli
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
8 Comments
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6412237
you may seeking somewhere to another pos,
or you close and reopen your file somewhere
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6412273
maybe you should use a var for storing your current pos,
instead of seeking relative
0
 
LVL 3

Expert Comment

by:rondi
ID: 6412675
Hi,

Please show the code for VerifySaveRec and LoadRecord

rondi.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 6

Expert Comment

by:wimmeyvaert
ID: 6412844
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
 
LVL 1

Author Comment

by:DanEgli
ID: 6413913
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
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6417903
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
 
LVL 1

Author Comment

by:DanEgli
ID: 6419859
Worth a shot. Thanks! I'll try it tonight.
0
 
LVL 27

Accepted Solution

by:
kretzschmar earned 50 total points
ID: 6420726
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

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…
Suggested Courses
Course of the Month3 days, 15 hours left to enroll

630 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question