Recent

Author Topic: Append data to typed file saves blank records  (Read 7635 times)

Ronan

  • Full Member
  • ***
  • Posts: 132
Append data to typed file saves blank records
« on: April 30, 2016, 07:00:34 pm »
Hi,

In order to append to the typed file I use the following code, but that append adds only last entered records and many blank records to the file. What am I doing wrong with the code ?

     
Code: Pascal  [Select][+][-]
  1. the structure of record is :
  2. TRecord = record
  3.  name :string[20]
  4.  standart:string[20];
  5.  
  6.  ...
  7.  ...
  8.  val :Integer;
  9. end;
  10.  
  11.  
  12.      var
  13.      rec :TRecord;
  14.  
  15.      if  FileExists(Dir_path+'custom_profiles.tan') then
  16.      begin
  17.       AssignFile(cus_file,Dir_Path+'custom_profiles.tan' );
  18.       filemode:= fmOpenReadWrite;
  19.       Reset(cus_File);
  20.  
  21.       Seek(cus_file, FileUtil.FileSize(dir_path+'custom_profiles.tan'));
  22.       rec.name:= ComboBox2.Text;
  23.  
  24.       rec.h := StrToFloat(LabeledEdit4.Text);
  25.       rec.b:= StrToFloat(LabeledEdit5.Text);;
  26.       rec.tf := StrToFloat(LabeledEdit6.Text);
  27.       rec.tw := StrToFloat(LabeledEdit7.Text);
  28.  
  29.       .......
  30.       ......
  31.       ......
  32.  
  33.       write(cus_file,rec);
  34.  
  35.       end;
  36.  

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Append data to typed file saves blank records
« Reply #1 on: April 30, 2016, 10:31:52 pm »
I assume cus_file is a typed file of TRecord.
Seek(f, x), where f is a typed file of record, moves the file pointer to the xth record in the file. If you use FileSize for x you will move it way beyond the end of the file (unless the record size is only one byte)!

You want something along these lines:
Code: Pascal  [Select][+][-]
  1. var
  2.   f: file of TRecord;
  3.   r: TRecord;
  4. begin
  5.   AssignFile(f, Dir_path+'custom_profiles.tan');
  6.   Filemode:=2;
  7.   Reset(f);
  8.   while not eof(f) do // move to end of file
  9.     Read(f, r);
  10.   // file pointer is now at end of file, so what is written now will be appended
  11.   // and not overwrite existing data
  12.  
  13. //  some routine to fill record with data you want appended
  14. ...
  15.   Write(f, r);
  16.   CloseFile(f);
  17. end;  
       
« Last Edit: May 01, 2016, 06:35:53 am by howardpc »

Ronan

  • Full Member
  • ***
  • Posts: 132
Re: Append data to typed file saves blank records[SOLVED]
« Reply #2 on: May 01, 2016, 09:32:53 am »
Thanks it really solved by problem, but I still wonder if there is more efficent way of getting end of file without iterating through all records.

linuxfan

  • Jr. Member
  • **
  • Posts: 57
Re: Append data to typed file saves blank records
« Reply #3 on: May 01, 2016, 09:56:50 am »
Use seek(): http://www.freepascal.org/docs-html/rtl/system/seek.html

You must also change reset() to reset(f, sizeof(Trecord)) first.
Then you can seek() to any record position.
« Last Edit: May 01, 2016, 10:03:54 am by linuxfan »

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Append data to typed file saves blank records
« Reply #4 on: May 01, 2016, 11:31:51 am »
On a typed file of record Reset automatically takes into account the size of the record, you do not need to include it as a parameter (though it does no harm to repeat it).

You can calculate the position of the last record and do something like this:
Code: Pascal  [Select][+][-]
  1.  f: file of TRecord;
  2.   r: TRecord;
  3.   recCount: int64;
  4. begin
  5.   recCount:=FileSize('file.dat') div SizeOf(TRecord);
  6.   AssignFile(f, 'file.dat');
  7.   Filemode:=2;
  8.   Reset(f);
  9.   Seek(f, recCount);    
  10.   // write the appended record here
  11.   CloseFile(f);
  12. end;

linuxfan

  • Jr. Member
  • **
  • Posts: 57
Re: Append data to typed file saves blank records
« Reply #5 on: May 02, 2016, 09:25:05 am »
> On a typed file of record Reset automatically takes into account the size of the record

This is nice, it's a pity it is not mentioned in the docs I've seen: http://www.freepascal.org/docs-html/rtl/system/reset.html

Three other things that *could* work, or that would be nice if they worked, are append() to a typed file, SeekEof(), and seek() to negative values (counted from EOF+1).

OutToPascal

  • New member
  • *
  • Posts: 7
Re: Append data to typed file saves blank records
« Reply #6 on: May 19, 2016, 04:47:31 pm »
I assume cus_file is a typed file of TRecord.
Seek(f, x), where f is a typed file of record, moves the file pointer to the xth record in the file. If you use FileSize for x you will move it way beyond the end of the file (unless the record size is only one byte)!   

I am wondering about the Seek(f,FileSize(f)) command.  Now, I guess things can change in the 33 years or so since it was published, but in the "TURBO Pascal Reference Manual" on Page 95 of the www.retroarchive.org/docs/tp3/tp3_14-16.pdf , for Seek it states,

Seek moves the file pointer is moved to the n'th component of the file denoted by FilVar.  n is an integer expression.  The position of the first component is 0.  Note that in order to expand a file it is possible to seek one component beyond the last component.  The statement Seek(FilVar, FileSize(FilVar)); thus places the file pointer at the end of the file (FileSize returns the number of components in the file, and as the components are numbered from zero, the returned number is one greater than the number of the last component.)

So in the past I've used the Seek(f,FileSize(f)) with Turbo Pascal without problem.  But now, using this more modern Freepascal version, there seems to be a difference in how FileSize works?  The manual states "n'th component of the file."

In the www.freepascal.org documentation, it states "Filesize returns the total number of records in the file F.  In cannot be invoked with a file of type Text."  So it also states "records" which I equate with "components" as in Turbo Pascal, but yet, I get an error(#217 I think) attempting to append a file in this manner.

Also, as a long-ago user of Turbo Pascal but a newbie with this, I don't remember ever having to use FileUtil.FileSize(f), it was always just FileSize(f).

One last question was what the FileMode=2 does, as I don't remember that either.

Thanks for any/all help.

I'm hoping this is somewhat like riding a bicycle, without the falling off part of course.
« Last Edit: May 19, 2016, 04:58:20 pm by OutToPascal »

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Append data to typed file saves blank records
« Reply #7 on: May 19, 2016, 05:54:28 pm »
In default mode FPC behaves just like you'd expect from TurboPascal. Including file of records.

I am missing a:
Code: Pascal  [Select][+][-]
  1. rewrite(f)
though. Instead of reset... ;) Same as 33 years ago, btw.
« Last Edit: May 19, 2016, 06:20:18 pm by Thaddy »
Specialize a type, not a var.

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Append data to typed file saves blank records
« Reply #8 on: May 20, 2016, 09:12:51 am »
In the www.freepascal.org documentation, it states "Filesize returns the total number of records in the file F.  In cannot be invoked with a file of type Text."  So it also states "records" which I equate with "components" as in Turbo Pascal, but yet, I get an error(#217 I think) attempting to append a file in this manner.

Also, as a long-ago user of Turbo Pascal but a newbie with this, I don't remember ever having to use FileUtil.FileSize(f), it was always just FileSize(f).

One last question was what the FileMode=2 does, as I don't remember that either.

There are (at least) two different FileSize() functions.
The FPC RTL function takes any file, f, as a parameter (as long as f is not a text file) and returns the 'size' where 'size' means the number of records in the file.
The Lazarus overloaded function of the same name gives you the size in bytes of any file with a given filename, i.e. you pass a string parameter to the FileUtil.FileSize() function, not a file.
These FileSize functions both return int64 values. However, the RTL function, as you noted from its documentation, returns the number of records in the file (which only equates to the 'overall size' if each record occupies only a single byte), whereas the Lazarus FileUtil.FileSize() function always returns the overall size of the file in bytes, whether it is a file of typed records, a text file or some other type of file.

Filemode is a global variable set by default in the RTL to a value 2 which indicates files will be opened for both reading and writing.
You can also set it to 0 (files are then opened for reading only) or to 1 (files are opened for writing only).
Modern practice is to prefer using streams for working with files. Filestream routines use enumerations (fmOpenRead, fmShareDenyNone etc.) to indicate to the OS what file operation is being requested. So  recent code rarely uses the FileMode variable.

 

TinyPortal © 2005-2018