Recent

Author Topic: Read and Readln both read only one line from file  (Read 622 times)

rnfpc

  • Jr. Member
  • **
  • Posts: 91
Read and Readln both read only one line from file
« on: June 27, 2019, 04:06:42 pm »
I have following text file:

Code: Pascal  [Select]
  1. C1,C2,C3,C4,C5
  2. 1,5,9,13,17
  3. 2,6,10,14,18
  4. 3,7,11,15,19
  5. 4,8,12,16,20
  6. 1,5,9,13,17
  7. 2,6,10,14,18
  8. 3,7,11,15,19
  9. 4,8,12,16,20
  10.  

I am trying to read whole of it in one string with following code:

Code: Pascal  [Select]
  1. {$mode objfpc}
  2. uses sysutils;
  3.  
  4. const
  5.   C_INFNAME = 'rosetta.csv';
  6.  
  7. var
  8.         infname: textfile;
  9.         filestr: string;
  10.         tfIn: TextFile;
  11.  
  12. begin
  13.         AssignFile(tfin, C_INFNAME);
  14.         try
  15.                 reset(tfin);  
  16.                 read(tfin, filestr);
  17.                 writeln(filestr);
  18.                 CloseFile(tfIn);       
  19.         except
  20.         on E: EInOutError do
  21.                 writeln('File handling error occurred. Details: ', E.Message);         
  22.         end;
  23. end.

However, the output is:
Code: Pascal  [Select]
  1. C1,C2,C3,C4,C5
  2.  

Same output is there if I use readln instead of read in code above.

Why only one line is being read? How can I read full text in file in one string? Thanks for your help.

madref

  • Hero Member
  • *****
  • Posts: 700
  • ..... A day not Laughed is a day not Lived !!
    • Nursing With Humour
Re: Read and Readln both read only one line from file
« Reply #1 on: June 27, 2019, 04:14:28 pm »

You don't check for the end of file (EOF) and make it a while-statement
Code: Pascal  [Select]
  1. AssignFile(tfin, C_INFNAME);
  2. While NOT(EOF(tfin)) DO
  3.   Begin
  4.     read(twin);
  5.     ....
  6.  


Google for it and see how it works
You treat a disease, you win, you lose.
You treat a person and I guarantee you, you win, no matter the outcome.

Lazarus 2.0.2 / FPC 3.0.4
Lazarus Trunc / FPC 3.0.4
Mac OS X Mojave

Kays

  • Full Member
  • ***
  • Posts: 182
  • Whasup!?
    • KaiBurghardt.de
Re: Read and Readln both read only one line from file
« Reply #2 on: June 27, 2019, 04:43:40 pm »
[…] text file […]
You can’t do this with a text variable. A textFile (= text) inherently knows and is structured as a sequence of lines. With read and readLn the new line character(s) will always be consumed.

Instead you have to use, e. g. a file of char and fill an appropriate variable on your own. Then you can see the #10 (or whatever lineEnding the file uses).

NB: There are smarter ways to read a CSV.
Yours Sincerely
Kai Burghardt

lucamar

  • Hero Member
  • *****
  • Posts: 2120
Re: Read and Readln both read only one line from file
« Reply #3 on: June 27, 2019, 04:47:27 pm »
Unlike ReadLn(), Read() will only read up to but not including an end of line and stop there. Subsequent Reads (which, BTW, you're not doing) will again find that end of line and return nothing.

What you need is something like this (untested!):
Code: Pascal  [Select]
  1. {$mode objfpc}
  2. uses sysutils;
  3.  
  4. const
  5.   C_INFNAME = 'rosetta.csv';
  6.  
  7. var
  8.   infname: textfile;
  9.   filestr, tmpStr: string;
  10.   tfIn: TextFile;
  11.  
  12. begin
  13.   AssignFile(tfin, C_INFNAME);
  14.   try
  15.     reset(tfin);
  16.     try
  17.       filestr := '';
  18.       while not EOF(tfin) do begin
  19.         ReadLn(tfin, tmpStr);
  20.         filestr := filestr + tmpStr + LineEnding;
  21.       end;
  22.       writeln(filestr);
  23.     finally
  24.       CloseFile(tfIn);
  25.     end;
  26.   except
  27.     on E: EInOutError do
  28.       writeln('File handling error occurred. Details: ', E.Message);
  29.   end;
  30. end.

Or you could just use ReadFileToString(), from the FileUtil unit of the LazUtils package:

Code: Pascal  [Select]
  1. {$mode objfpc}
  2. uses FileUtil;
  3.  
  4. const
  5.   C_INFNAME = 'rosetta.csv';
  6.  
  7. var
  8.   filestr: string;
  9.  
  10. begin
  11.   try
  12.     filestr := ReadFileToString(C_INFNAME);
  13.     writeln(filestr);
  14.   except
  15.     on E: EInOutError do
  16.       writeln('An error occurred. Details: ', E.Message);
  17.   end;
  18. end.
« Last Edit: June 27, 2019, 04:55:58 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.2/2.0.4  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Read and Readln both read only one line from file
« Reply #4 on: June 27, 2019, 04:59:12 pm »
Use FileSize to get the size of the file
Give a string the same size
Read the whole file using BlockRead in one go into the string you prepared in the previous step:
Code: Pascal  [Select]
  1. program project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. const
  6.   C_INFNAME = 'rosetta.csv';
  7.  
  8. var
  9.   f: file;
  10.   s: String;
  11.   Len: Int64;
  12. begin
  13.   Assign(f, C_INFNAME);
  14.   Reset(f,1);
  15.  
  16.   Len := FileSize(f);
  17.   SetLength(s, Len);
  18.  
  19.   BlockRead(f, s[1], Len);
  20.   Close(f);
  21.  
  22.   writeln(s);
  23.  
  24.   ReadLn;
  25. end.


Or use streams

Edit:
Changed AssignFile and CloseFile to Assign and Close as per Thaddy's objection.
« Last Edit: June 27, 2019, 07:37:08 pm by engkin »

Thaddy

  • Hero Member
  • *****
  • Posts: 9275
Re: Read and Readln both read only one line from file
« Reply #5 on: June 27, 2019, 06:46:51 pm »
I object to using assignfile and closefile: these are re directions and not even inlined to assign() and Close() which is proper Pascal syntax. This silly syntax should be deprecated.
Furthermore: read() reads a variable of the size of file type. If that is untyped, it will read a char at a time. Readln() reads up-to-and -including a LineBreak.

But the above example is correct except for my first comment line here, it still works but is not optimal nor is it  standard Pascal.

(There is an exception, codepage related, though, as I explained last week....  O:-) )
« Last Edit: June 27, 2019, 06:51:42 pm by Thaddy »
also related to equus asinus.

winni

  • Hero Member
  • *****
  • Posts: 549
Re: Read and Readln both read only one line from file
« Reply #6 on: June 27, 2019, 07:35:22 pm »
The advantage of filestreams and other high level routines is, that nobody knows how to read a simple textfile. That is pascal lection 3.

The syntax for textfile, assignfile and closefile comes from delphi 1. They were intoduced to avoid trouble with Tform1.close and TForm1.assign.

The very basic solution goes like this:


Code: Pascal  [Select]
  1. procedure readCSV (Fname : String; separator: Char);
  2. var s, item : string;
  3.       st : TStringList;
  4.       txt : textFile;
  5.       p : integer;
  6. begin
  7. st := TStringList.create;
  8. assignFile (txt, fname);
  9. reset (txt);
  10. while not eof (txt) do
  11.   begin
  12.      readln (txt,s);
  13.      repeat
  14.      p := pos (separator,s);
  15.      if p > 0 then  
  16.           begin
  17.           item := copy (s,1,p-1);
  18.           delete (s,1,p);
  19.           st.add (item);
  20.           end;
  21.     until p = 0;
  22.      if s <> '' then st.add(s);
  23.       // do something with the items now in st
  24.      st.clear;
  25.   end; // while
  26. closefile (txt);
  27. st.free;
  28. end; // proc
  29.  
  30.  


Have a nice day
Winni

rnfpc

  • Jr. Member
  • **
  • Posts: 91
Re: Read and Readln both read only one line from file
« Reply #7 on: June 27, 2019, 07:45:24 pm »
Thanks everyone for very useful suggestions.

Procedure readCSV is good. Can it be made into a function readCSV which returns an Array of TStringList?

Thaddy

  • Hero Member
  • *****
  • Posts: 9275
Re: Read and Readln both read only one line from file
« Reply #8 on: June 27, 2019, 08:32:26 pm »
The very basic solution goes like this:
Your suggestion about streams is good, using a string list, however, is bad advice since it does not scale,
Teaching bad habits is not a good idea.
( I would fire you, or at least would demand some thought and a warning, if you were in my employment!!! )

Streams scale, lists do not scale. This is all basics.
« Last Edit: June 27, 2019, 08:35:40 pm by Thaddy »
also related to equus asinus.

Handoko

  • Hero Member
  • *****
  • Posts: 3222
  • My goal: build my own game engine using Lazarus
Re: Read and Readln both read only one line from file
« Reply #9 on: June 27, 2019, 08:47:29 pm »
@rnfpc

There are many ways for file reading/writing, each of them has their own advantages/disadvantages. If you're interested, I ever wrote some demos, maybe you can learn something from the codes:

https://forum.lazarus.freepascal.org/index.php/topic,43045.msg307111.html#msg307111

https://forum.lazarus.freepascal.org/index.php/topic,37766.msg254800.html#msg254800

https://forum.lazarus.freepascal.org/index.php/topic,39769.msg274036.html#msg274036

winni

  • Hero Member
  • *****
  • Posts: 549
Re: Read and Readln both read only one line from file
« Reply #10 on: June 27, 2019, 09:09:22 pm »
@thaddy

And the stream scales and scales and scales and then there is not enough RAM. And nobody knows how to solve the problem the good old way. So they buy more RAM. Very good design.

And if you're looking for slaves: I'm not the right one!



@rnfpc

An Array of TStringlist sounds like an ugly design. But you could think about a two-dimensional array of string for your items.

Type TArrayOfArrayOfString = Array Of Array of String;

Have a nice day.