* * *

Author Topic: Read line from textfile  (Read 864 times)

lolka_bolka

  • Newbie
  • Posts: 3
Read line from textfile
« on: April 24, 2018, 08:25:10 pm »
Guys, what the heck do I wrong.

Code: Pascal  [Select]
  1. procedure TmainForm.readProcutsBtnClick(Sender: TObject);
  2.  
  3. var
  4.   i: Integer;
  5.   productCity: string;
  6.   productName: string;
  7.   productCount: Integer;
  8.   productFileIn: TextFile;
  9.  
  10. begin
  11.  
  12.   assignFile(productFileIn, 'termek.txt');
  13.   reset(productFileIn);
  14.   i := 0;
  15.   while not EOF(productFileIn) do
  16.   begin
  17.     i := i + 1;
  18.     readLn(productFileIn, productCity, productName,  productCount);
  19.   end;
  20.   closefile(productFileIn);
  21.  
  22. end;                                                    
  23.  

It works if I am using this:

Code: Pascal  [Select]
  1. readLn(productFileIn, productCity);
  2.  

Whole line will be in productCity as a string.

My file is a space separated txt.

How can I read into the 3 variables?

howardpc

  • Hero Member
  • *****
  • Posts: 2716
Re: Read line from textfile
« Reply #1 on: April 24, 2018, 09:11:04 pm »
You have to parse the value read from the file.

Code: Pascal  [Select]
  1. procedure TForm1.readProcutsBtnClick(Sender: TObject);
  2. var
  3.   productCity: string;
  4.   productName: string;
  5.   productCount, p: Integer;
  6.   txtf: TextFile;
  7.   s: String;
  8. begin
  9.   AssignFile(txtf, 'termek.txt');
  10.   try
  11.     Reset(txtf);
  12.     ReadLn(txtf, s);
  13.     if Length(s) > 5 then
  14.       begin
  15.         p := Pos(' ', s);
  16.         if p > 0 then begin
  17.           productCity := Copy(s, 1, p-1);
  18.           Delete(s, 1, p);
  19.         end;
  20.         p := Pos(' ', s);
  21.         if p > 0 then begin
  22.           productName := Copy(s, 1, p-1);
  23.           Delete(s, 1, p);
  24.         end;
  25.         p := Length(s);
  26.         if p > 0 then
  27.           productCount := StrToIntDef(Trim(s), -1);
  28.       end;
  29.   finally
  30.     CloseFile(txtf);
  31.   end;
  32. end;
                           

Handoko

  • Hero Member
  • *****
  • Posts: 2443
  • My goal: build my own game engine using Lazarus
Re: Read line from textfile
« Reply #2 on: April 24, 2018, 09:13:10 pm »
Or you can you Thaddy's solution:

Read the line as usual but use TStringList to separate the items:

01. Set TStringList.Delimiter to ' ' (a space char);
02. Set TStringList.StrictDelimiter to True;
03. Set TStringList.DelimitedText to the string read from the file
04. The result strings are in TStringList.Strings[ i ]


Read more:
http://forum.lazarus-ide.org/index.php/topic,33644.msg218291.html#msg218291

ASerge

  • Hero Member
  • *****
  • Posts: 862
Re: Read line from textfile
« Reply #3 on: April 24, 2018, 09:37:23 pm »
Code: Pascal  [Select]
  1. begin
  2.   AssignFile(txtf, 'termek.txt');
  3.   try
  4.     Reset(txtf);
  5. ...
  6.   finally
  7.     CloseFile(txtf);
  8.   end;
  9. end;
                           
The AssignFile procedure does not open the file, so the try position must be lower than the Reset procedure. For example, if the file does not exist, CloseFile will throw an additional exception because It cannot close the file that did not open.

howardpc

  • Hero Member
  • *****
  • Posts: 2716
Re: Read line from textfile
« Reply #4 on: April 24, 2018, 09:46:33 pm »
A very good comment, thanks for pointing this out.

molly

  • Hero Member
  • *****
  • Posts: 2345
Re: Read line from textfile
« Reply #5 on: April 24, 2018, 09:49:42 pm »
Guys, what the heck do I wrong.
Gals also ok ?  :P

What you're doing wrong is that you make a wrong assumption.

Quote
My file is a space separated txt.
A space is a (valid) character. A string consist of characters, ergo the readln procedure is unable to determine which part of your data belongs to what string variable.

Luckily there is special (control) character that is able to solve that, which is called SUB. Perhaps you've heard of the special keyboard-sequence ctrl-z, which (when supported by your editor) is able to create this character for you. Any hex-editor will do as well. Edit your file and separate your 'fields' with this character (*). Best would probably be to save your data in the correct way to begin with (if you have nay control over that).

For sure the answers given so far are sufficient to solve your problem but the cause of your evil was started with the wrong assumption  ;)


edit: (*)
So much for delphi compatiblity. Does nto work with Free Pascal. Looking for the correct separator.
« Last Edit: April 24, 2018, 10:02:31 pm by molly »

Bart

  • Hero Member
  • *****
  • Posts: 3029
    • Bart en Mariska's Webstek
Re: Read line from textfile
« Reply #6 on: April 24, 2018, 10:09:57 pm »
Doesn't  a ^Z (Ctrl+Z) character in a textfile denote "end of file"?
At least it did so in old TP era.

Bart

molly

  • Hero Member
  • *****
  • Posts: 2345
Re: Read line from textfile
« Reply #7 on: April 24, 2018, 10:27:30 pm »
@bart, yes indeed it does (besides other uses later on).

I would have to look at readln implementation to see how exactly fpc handles it, for the time being assuming indeed eof. SUB seems to work for (old) delphi, but i would have to verify with tp/bp.

To stay on topic for TS: think about this storage format  you are currently using (separating individual 'fields' with a space character) because what happens if your product name contains a space character ?

ASerge

  • Hero Member
  • *****
  • Posts: 862
Re: Read line from textfile
« Reply #8 on: April 24, 2018, 11:00:32 pm »
A very good comment, thanks for pointing this out.
With your connivance :) I'll add another comment.
The code to extract the word (Pos+Copy+Delete) must be in a separate function. Apart from obvious advantages such as improved readability and size reduction, it is more deterministic.
Illustrate. The example above does not specify what is done with read variables. Let them is transmitted to some procedure DoWork.
As a result, the code will be similar to this:
Code: Pascal  [Select]
  1. AssignFile(txtf, 'termek.txt');
  2. Reset(txtf);
  3. try
  4.   while not Eof(txtf) do
  5.   begin
  6.     // Your code
  7.     DoWork(productCity, productName, productCount);
  8.   end;
  9. ...
What happens if the input string contains incomplete data? Then the data from the previous iteration(s) will be transferred to the DoWork procedure. This is not a deterministic result.
Now extract the code to a separate function, for example:
Code: Pascal  [Select]
  1. function ExtractWord(var S: string): string;
  2. var
  3.   SpacePos: Integer;
  4. begin
  5.   SpacePos := Pos(' ', S);
  6.   if SpacePos = 0 then
  7.     SpacePos := Length(S) + 1;
  8.   Result := Copy(S, 1, SpacePos - 1);
  9.   Delete(S, 1, SpacePos);
  10. end;
and do
Code: Pascal  [Select]
  1. productCity := ExtractWord(s);
  2. productName := ExtractWord(s);
  3. productCount := StrToIntDef(ExtractWord(s), -1); // Yes do ExtractWord to support future extended format of file
  4. DoWork(productCity, productName, productCount);
In this case, if the input data is incomplete, we always pass null values.

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus