Recent

Author Topic: need help with show a file like this  (Read 40862 times)

GMP_47

  • Jr. Member
  • **
  • Posts: 60
Re: need help with create a file like this
« Reply #15 on: September 22, 2015, 04:12:55 pm »
Why the serial is not on the file?
It IS in the file. The first 2 bytes of your file are $37 and $3D. Since you mentioned a serial could be 43112 it can't be an signed integer which goes from -32,768 to 32,767. So it has to be an unsigned integer/word. So either 15.671 or 14.141 (if hi and low bytes are swapped). So there is your serial. (Since the hi/low of the fieldnrs are swapped I think it's also the latter for the serial)

This is done without classes and I dont have the time right now to learn OOP.
I'm not sure where you see OOP in my example???? I didn't program any OOP. I used TFileStream (which uses OOP) but for using it you don't need OOP yourself at all. So you don't have to learn anything (except how to use TFileStream which is far easier than using assign/reset/read).

But if you really don't want to use TFileStream you can just remove the uses clause at the top and create your read-file. You need to open the file with Reset(f,1) because you need to be able to read byte by byte.

Code: [Select]
var
  BinaryStream: File;

  procedure myRead(var Buffer; Size: Integer);
  begin
    BlockRead(BinaryStream, Buffer, Size);
  end;

begin
  assign(BinaryStream, 'EXAMEN2.dat');
  reset(BinaryStream, 1);
  // don't read the whole header at once but piece by peice
  myRead(Header.Serial, 2);
  myRead(Header.Filename[0], 1);
  myRead(Header.Filename[1], ord(Header.Filename[0]));
  myRead(Header.Date, 2);
  myRead(Header.Fieldnrs, 2);
  //....

The rest is the same as my example with every BinaryStream.Read() replaced by myRead() (and the try/finally removed with a Close() at the end).

You should be able to adjust this all yourself. You should also be able to translate the date-word to a full-date with the description given.

Unfortunately, if this is a course work, then you might have to accept a fail mark.
Not a bad thing, because the work will only get harder, and giving you a solution is unfair on the people who worked hard to learn how to do this.
Giving you a complete solution would not only be unfair on the people who worked hard to learn how to do this but it would also be unfair to you for not giving you the opportunity to learn it. Without learning these basics you end up in a lot more trouble when the assignments get harder.

So with what I showed you so far (and if you understand it) you should be able to read the rest of the file.
but TFileStream is a class. Bloodshed doenst admit classes. this is not a course work. I'm allowed to ask for help and most people did this in C in teams.

rvk

  • Hero Member
  • *****
  • Posts: 6675
Re: need help with create a file like this
« Reply #16 on: September 22, 2015, 04:16:27 pm »
but TFileStream is a class. Bloodshed doenst admit classes.
So follow my direction in making a myRead() and change it like I showed and you'll be able to read the file.

You need to use BlockRead because your file is untyped. (There is no specific static record-structure, it's all variable due to the variable length of the strings)


F.Y.I. Dev-Pascal (from Bloodshed) does allow Classes. You just need to add "C:\Dev-Pas\units\fcl\" to the Pascal-unit and Library directory under options.
« Last Edit: September 22, 2015, 04:27:28 pm by rvk »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8786
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: need help with create a file like this
« Reply #17 on: September 22, 2015, 07:02:59 pm »
this is not a course work. I'm allowed to ask for help and most people did this in C in teams.
You've got the help from rvk, now use it well, don't make him do the task for you. You are allowed to ask for help, not asking someone to do it ENTIRELY for you. Programming is not (only) a knowledge, it's a skill. You do it, you will be capable. Someone else does it, that person will be capable, not you, NEVER you.
F.Y.I. Dev-Pascal (from Bloodshed) does allow Classes. You just need to add "C:\Dev-Pas\units\fcl\" to the Pascal-unit and Library directory under options.
VERY DAMN OLD FPC that's bunldled with it does have classes unit, the oldness is its only problem. This task should be solvable even with that VERY DAMN OLD FPC (no need for TFileStream, basic Pascal I/O, as rvk has pointed, is enough).

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12050
  • FPC developer.
Re: need help with create a file like this
« Reply #18 on: September 22, 2015, 09:23:16 pm »
dev-pascal comes with 1.9.2 which was the first usable version of the 2.x.x series. It should be quite ok for student assignments, and definitely has classes.

(though I wouldn't touch it with a bargepole)

GMP_47

  • Jr. Member
  • **
  • Posts: 60
Re: need help with create a file like this
« Reply #19 on: September 22, 2015, 09:35:09 pm »
this is not a course work. I'm allowed to ask for help and most people did this in C in teams.
You've got the help from rvk, now use it well, don't make him do the task for you. You are allowed to ask for help, not asking someone to do it ENTIRELY for you. Programming is not (only) a knowledge, it's a skill. You do it, you will be capable. Someone else does it, that person will be capable, not you, NEVER you.
F.Y.I. Dev-Pascal (from Bloodshed) does allow Classes. You just need to add "C:\Dev-Pas\units\fcl\" to the Pascal-unit and Library directory under options.
VERY DAMN OLD FPC that's bunldled with it does have classes unit, the oldness is its only problem. This task should be solvable even with that VERY DAMN OLD FPC (no need for TFileStream, basic Pascal I/O, as rvk has pointed, is enough).
I dont intend for others to do it for me.
So I should read what this classes do. I dont have to create them because they are integrated in pas by default, right?
I feel really sick today, I'll retake this tomorrow.

rvk

  • Hero Member
  • *****
  • Posts: 6675
Re: need help with create a file like this
« Reply #20 on: September 22, 2015, 09:49:23 pm »
So I should read what this classes do. I dont have to create them because they are integrated in pas by default, right?
You could do it with the TFileStream method (I showed first) or with the myRead() which uses Assign/Reset & BlockRead (I showed second). Both methods should work fine. So it's up to you (or which you understand best).

If you go with TFileStream you only need to include that path to units\fcl\ in the settings. After that you can use "uses Classes" and it's all in there, ready for you to use.

Feel better...

GMP_47

  • Jr. Member
  • **
  • Posts: 60
Re: need help with create a file like this
« Reply #21 on: September 27, 2015, 03:08:59 am »
Untyped means it's just a sequence of data (bytes)
So I create a myRead procedure so that I can BlockRead every data from an untyped file, giving me a size of BYTES stored in Buffer.


Code: [Select]
uses SysUtils;
var
  BinaryStream: File;
  nrs: Integer;

procedure myRead(var Buffer; Size: Integer);
  begin
    BlockRead(BinaryStream, Buffer, Size);
  end;

begin
  assign(BinaryStream, 'C:\Dev-Pas\EXAMEN2.dat');
  reset(BinaryStream, 1);  //each with respective number of bytes
  myRead(Header.Serial, 2);
  myRead(Header.Filename[0], 1);
  myRead(Header.Filename[1], ord(Header.Filename[0])); //ordinal val
  myRead(Header.Date, 2);
  myRead(Header.Fieldnrs, 2);

  Header.Serial := Swap(Header.Serial);  //why the swap?
  Header.Fieldnrs := Swap(Header.Fieldnrs);

  SetLength (Fields, Header.Fieldnrs); //n° of custom fields are 4 so fields=4
  for nrs := 0 to Header.Fieldnrs - 1 do  //from 0 up to 3
  begin
       myRead (Fields [nrs].Fieldnr, 2);
       Fields[nrs].Field := Swap (Fields [nrs].Fieldnr);
       myRead (Fields[nrs].Fieldname[0],1);
       myRead (Fields[nrs].Fieldname[1], ord(Fields[nrs].Fieldname[0]));
  end;

       Writeln('Serial: ', Header.Serial);  //show data from the header
       Writeln('Filename: ', Header.Filename);
       Writeln ('Date: ', Header.Date);
       Writeln ('Fieldnrs: ',Header.Fieldnrs);

       for nrs := 0 to Header.Fieldnrs - 1 do
       begin
            Writeln (Fields[nrs].Fieldnr,':',Fields[nrs].Fieldname);
       end;
Close (BinaryStream, 1);
ReadKey;
end.
what is the number in Header.Filename[X] for?

What's the bytes Swap for?
If you have 1234. you swap it, you get 3412. right?

I want to know how is it up to this point.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: need help with create a file like this
« Reply #22 on: September 27, 2015, 03:53:14 am »
why the swap?
The fantastic engineer who wrote up that assignment and used such horrible outdated structures forgot to tell you about endianess.

Please don't use swap(), rather figure out in which endianness the data is structured, then use either BEtoN or LEtoN

Quote
what is the number in Header.Filename[X] for?
Explained in the assignment that you posted yourself. Have you ever taken even a minor glimpse at it ? And i don't understand even one word of Spanish  >:(

Quote
What's the bytes Swap for?
If you have 1234. you swap it, you get 3412. right?
If the number you've written down is meant to be interpreted as a hexadecimal number, then yes.

GMP_47

  • Jr. Member
  • **
  • Posts: 60
Re: need help with create a file like this
« Reply #23 on: September 27, 2015, 05:09:33 am »
Quote
Quote
what is the number in Header.Filename[X] for?
Explained in the assignment that you posted yourself. Have you ever taken even a minor glimpse at it ? And i don't understand even one word of Spanish  >:(

minor glimpse?
I dont know what that number between [] means. after the , is the size. I know that.
« Last Edit: September 27, 2015, 05:11:48 am by GMP_47 »

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: need help with create a file like this
« Reply #24 on: September 27, 2015, 05:43:32 am »
minor glimpse?
That means: take a short look with your eyes (as in reading).

Quote
I dont know what that number between [] means. after the , is the size. I know that.
Ah ok. You could have figured that out yourself from having taken a look at the described data structure in your pdf, but indeed would be a bit harder to figure out.

The technical explanation is described here.

A string type declared in Pascal can be considered an array of characters, where the zero position [0] inside a string denotes the actual length of the string. The first index [1] denotes the first character of the string, etc.

Do note however, that this is for short strings. Things can get more complicated when using unicode strings, but please consider that of no concern for you at this moment.

PS: i hoped to find this being explained somewhere on the free pascal wiki or in one of the accompanied manuals, but this is all i could come up with  :o
« Last Edit: September 27, 2015, 06:06:57 am by molly »

rvk

  • Hero Member
  • *****
  • Posts: 6675
Re: need help with create a file like this
« Reply #25 on: September 27, 2015, 02:57:37 pm »
what is the number in Header.Filename[X] for?
Like you might (now) already know the ShortString (old pascal type string) is comprised of a length byte followed by the actual characters. The length byte is stored in String[0] (followed by length times character). It might have been more clear if I did this (below) but I just skipped the helper variable and stored the length directly in Filename[0] before actually reading the characters.
Code: [Select]
myRead(BinaryStream, StringLength, 1);
Header.Filename[0] := chr(StringLength); // <- set the stringlength
myRead(BinaryStream, Header.Filename[1], StringLength); // <- read the actual character beginning at [1]

What's the bytes Swap for?
Like molly already explained, this file is probably created on a Big-endian based system (e.g. powerpc). While Intel-processors are all Little-endian based (see wiki) we need to swap the bytes when reading Big-endian based numbers. I assumed we all were on Little-endian based machines (hence my use of swap()) but like molly pointed out this might not always be the case. Using BEtoN() (Big-endian to Native) this will all be automatically done if needed (i.e. on a powerpc it does nothing and on an intel-system it does the swap).

I want to know how is it up to this point.
A few points:
  • I don't see any records and variable definitions in your file
  • You have Fields[nrs].Field somewhere while I had Fields[nrs].Fieldnr
  • Close doesn't take any second parameter. (only the Reset() does)
  • The Readkey; could just be a Readln;
After that it should work fine.

(Did this example of yours compile for you?)

GMP_47

  • Jr. Member
  • **
  • Posts: 60
Re: need help with create a file like this
« Reply #26 on: September 27, 2015, 06:12:00 pm »
Quote
I don't see any records and variable definitions in your file
uhm woops... I had it in other file (getting error in Fields: array of TFields; )
Code: [Select]
program read_binary;
uses Classes, SysUtils;
type
  THeader = record
    Serial: Word;   //2 bytes
    Filename: String[255];  //1 byte
    Date: Word;  //2 bytes
    Fieldnrs: Word;  //2 bytes
  end;
  TFields = record
    Fieldnr: Word;   //2 bytes
    Fieldname: String[255];   //1 byte
  end;
var
  BinaryStream: File;
  Header: THeader;
  Fields: array of TFields;  //Fatal: Syntax error, OF expected but ; found
  nrs: Integer;

procedure myRead(var Buffer; Size: Integer);
  begin
    BlockRead(BinaryStream, Buffer, Size);
  end;

begin
  assign(BinaryStream, 'C:\Dev-Pas\EXAMEN2.dat');
  reset(BinaryStream, 1);
  myRead(Header.Serial, 2);
  myRead(Header.Filename[0], 1);
  myRead(Header.Filename[1], ord(Header.Filename[0]));
  myRead(Header.Date, 2);
  myRead(Header.Fieldnrs, 2);

  Header.Serial := Swap(Header.Serial);
  Header.Fieldnrs := Swap(Header.Fieldnrs);

  SetLength (Fields, Header.Fieldnrs);
  for nrs := 0 to Header.Fieldnrs - 1 do
  begin
       myRead (Fields[nrs].Fieldnr, 2);
       Fields[nrs].Fieldnr := Swap (Fields [nrs].Fieldnr);
       myRead (Fields[nrs].Fieldname[0],1);
       myRead (Fields[nrs].Fieldname[1], ord(Fields[nrs].Fieldname[0]));
  end;

       Writeln ('Serial: ', Header.Serial);
       Writeln ('Filename: ', Header.Filename);
       Writeln ('Date: ', Header.Date);
       Writeln ('Fieldnrs: ',Header.Fieldnrs);

       for nrs := 0 to Header.Fieldnrs - 1 do
       begin
            Writeln (Fields[nrs].Fieldnr,':',Fields[nrs].Fieldname);
       end;
Close(BinaryStream);
ReadKey;
end.

rvk

  • Hero Member
  • *****
  • Posts: 6675
Re: need help with create a file like this
« Reply #27 on: September 27, 2015, 06:40:09 pm »
Classes are not needed because you don't use TFileStream.

getting error in Fields: array of TFields;
DAMN. Just checked the version of FPC with dev-pas (like Leledumbo already mentioned). It's 1.0.6 from 2002. I'm not sure it can handle dynamic arrays yet. (who knows if it does?)

Then the question arises... are you committed to this very, very, very old version of FPC and Dev-pascal? Can't you just use FPC and the console fp.exe? Or even use Lazarus and create a console application with it?

If you need to keep using Dev-pascal with the old FPC you can change the dynamic array Fields into a static one. But you need to specify the maximum number of fields you are expecting.

Code: [Select]
  Fields: array[0..10] of TFields; // <-- maximum fields = 11
...
  //SetLength (Fields, Header.Fieldnrs); // <-- no need to set the length
« Last Edit: September 27, 2015, 06:54:56 pm by rvk »

GMP_47

  • Jr. Member
  • **
  • Posts: 60
Re: need help with create a file like this
« Reply #28 on: September 27, 2015, 07:17:49 pm »
It lives!
Code: [Select]
program read_binary;
uses SysUtils;
type
  THeader = record
    Serial: Word;   //2 bytes
    Filename: String[255];  //1 byte
    Date: Word;  //2 bytes
    Fieldnrs: Word;  //2 bytes
  end;
  TFields = record
    Fieldnr: Word;   //2 bytes
    Fieldname: String[255];   //1 byte
  end;
var
  BinaryStream: File;
  Header: THeader;
  Fields: array [0..10] of TFields;
  nrs: Integer;

procedure myRead(var Buffer; Size: Integer);
  begin
    BlockRead(BinaryStream, Buffer, Size);
  end;

begin
  assign(BinaryStream, 'C:\Dev-Pas\EXAMEN2.dat');
  reset(BinaryStream, 1);
  myRead(Header.Serial, 2);
  myRead(Header.Filename[0], 1);
  myRead(Header.Filename[1], ord(Header.Filename[0]));
  myRead(Header.Date, 2);
  myRead(Header.Fieldnrs, 2);

  Header.Serial := Swap(Header.Serial);
  Header.Fieldnrs := Swap(Header.Fieldnrs);

  //SetLength (Fields, Header.Fieldnrs);
  for nrs := 0 to Header.Fieldnrs - 1 do
  begin
       myRead (Fields[nrs].Fieldnr, 2);
       Fields[nrs].Fieldnr := Swap (Fields [nrs].Fieldnr);
       myRead (Fields[nrs].Fieldname[0],1);
       myRead (Fields[nrs].Fieldname[1], ord(Fields[nrs].Fieldname[0]));
  end;

       Writeln ('Serial: ', Header.Serial);
       Writeln ('Filename: ', Header.Filename);
       Writeln ('Date: ', Header.Date);
       Writeln ('Fieldnrs: ',Header.Fieldnrs);

       for nrs := 0 to Header.Fieldnrs - 1 do
       begin
            Writeln ('Campo [codigo: ',Fields[nrs].Fieldnr,', ','descripcion: ',Fields[nrs].Fieldname ,']' );
       end;
Close(BinaryStream);
ReadLn;
end.
got something wrong with the date.
Now I have to show the Field according to its number. and the FieldData.
the crappy thing is: I have to update the date with the current system's YYYY/MM/DD but SysUtils's got GetDate. I could use that?

edit: modified how to show example data.
If I remove the SWAP the program shuts down (like if there was no ReadLn).
« Last Edit: September 27, 2015, 07:40:05 pm by GMP_47 »

rvk

  • Hero Member
  • *****
  • Posts: 6675
Re: need help with create a file like this
« Reply #29 on: September 27, 2015, 07:31:23 pm »
got something wrong with the date.
Now I have to show the Field according to its number. and the FieldData.
the crappy thing is: I have to update the date with the current system's YYYY/MM/DD but SysUtils's got GetDate. I could use that?
No. I saw somewhere in your pdf that the data field is comprised of 7 bits for the year, 4 bits for the month and 5 bits for the day. So you need to do some bit-shifting to get the correct values for year, month and day.

And I think the year is an offset of 2000. You can see it at the end of that pdf but I can't read that language (Spanish?).

I'll help you along some...  :D Very rudimentary code:
Code: [Select]
  Header.Date := BEtoN(Header.Date);
  Writeln('Year offset to 2000: ', (Header.Date and %1111111000000000) shr (5+4));
  Writeln('Month: ', (Header.Date and %0000000111100000) shr 5);
  Writeln('Day: ', (Header.Date and %0000000000011111));
You see I do a bitwise AND to exclude the other bits in the field and after that I shift the bits to the right until the important bits are all at the end.

For writing you should do a shift of the bits to the left and an OR.

If you don't understand bitwise operations you might want to read up on them:
https://en.wikipedia.org/wiki/Bitwise_operation
(with that you should be able to do anything with the date)
« Last Edit: September 27, 2015, 07:50:31 pm by rvk »

 

TinyPortal © 2005-2018