Difference between revisions of "Read"
m (Emphasize the difference between read and readln) |
(→Signature: read from typed file, only basis type variables permitted) |
||
(35 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
{{read}} | {{read}} | ||
− | |||
− | |||
− | + | The procedures <syntaxhighlight lang="pascal" inline>read</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight> retrieve data from a [[Text|<syntaxhighlight lang="pascal" inline>text</syntaxhighlight> file]] (such as <syntaxhighlight lang="pascal" inline>input</syntaxhighlight>, the command line interface, or any file on disk). | |
+ | They are defined as part of the [[Standard Pascal|Pascal]] programming language. | ||
+ | Everyone can expect them to work no matter which compiler has been used. | ||
− | + | In [[Property|<syntaxhighlight lang="pascal" inline>property</syntaxhighlight>]] definitions the [[Reserved word|reserved word]] <syntaxhighlight lang="pascal" inline>read</syntaxhighlight> is used to direct read access. | |
− | + | This article deals with the procedures <syntaxhighlight lang="pascal" inline>read</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight>. | |
− | + | See [[Object|<syntaxhighlight lang="pascal" inline>object</syntaxhighlight>]] and related articles for the occurrence of <syntaxhighlight lang="pascal" inline>read</syntaxhighlight> in the context of properties. | |
− | |||
− | |||
− | + | == Behavior == | |
− | + | === Signature === | |
− | + | <syntaxhighlight lang="pascal" inline>Read</syntaxhighlight> as well as <syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight> share almost the same identical formal signature. | |
+ | However a formal signature is omitted here, since you can not write their signatures in Pascal. | ||
+ | Therefore a description follows: | ||
− | + | As an optional first parameter a <syntaxhighlight lang="pascal" inline>text</syntaxhighlight> variable can be specified where data are read from. | |
+ | <syntaxhighlight lang="pascal" inline>Read</syntaxhighlight> is additionally capable of reading from a [[typed files|typed <syntaxhighlight lang="pascal" inline>file</syntaxhighlight>]] variable (<syntaxhighlight lang="pascal" inline>file of recordType</syntaxhighlight>). | ||
− | + | If no source is specified, [[Input|<syntaxhighlight lang="pascal" inline>input</syntaxhighlight>]] is assumed. | |
+ | Thereafter any number of variables can be specified, but at least one has to be present. | ||
+ | They have to be either [[Char|<syntaxhighlight lang="pascal" inline>char</syntaxhighlight>]], [[Integer|<syntaxhighlight lang="pascal" inline>integer</syntaxhighlight>]], [[Real|<syntaxhighlight lang="pascal" inline>real</syntaxhighlight>]], or [[String|<syntaxhighlight lang="pascal" inline>string</syntaxhighlight>]]. | ||
+ | If you have specified a typed file as the source, all variables have to be of the file’s underlying base type. | ||
− | + | Earlier versions of [[FPC]] also allowed reading variables of the type [[PChar|<syntaxhighlight lang="pascal" inline>PChar</syntaxhighlight>]]. This has been removed, since no buffer checking is possible with those. | |
+ | In the case of typed files as source, only variables of the [[File|file’s]] record type can be specified. | ||
− | + | === Execution === | |
− | + | Calling <syntaxhighlight lang="pascal" inline>read</syntaxhighlight>/<syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight> will place the read (and possibly accordingly interpreted) values to the given variables. | |
− | The | + | The order of variables matters. For instance, when the following program: |
− | [[ | + | <syntaxhighlight lang="pascal"> |
+ | program readDemo(input, output, stderr); | ||
+ | var | ||
+ | i: integer; | ||
+ | c: char; | ||
+ | begin | ||
+ | readLn(i, c); | ||
+ | end. | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | is supplied with: | ||
+ | |||
+ | <syntaxhighlight lang="text"> | ||
+ | 42 x | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | everything is fine. | ||
+ | |||
+ | <syntaxhighlight lang="pascal" inline>i</syntaxhighlight> will become <syntaxhighlight lang="pascal" inline>42</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>c</syntaxhighlight> will become <syntaxhighlight lang="pascal" inline>'x'</syntaxhighlight>. | ||
+ | But the reverse input order | ||
+ | <syntaxhighlight lang="text"> | ||
+ | x 42 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | will yield a [[runtime error|run-time error]] (in this case RTE 106). | ||
+ | |||
+ | Once data are read and stored, they are “consumed”, thus cannot be retrieved otherwise, but via the variables only. | ||
+ | However, data are read up to the variable’s size limits. | ||
+ | E. g. a fixed length <syntaxhighlight lang="pascal" inline>string[24]</syntaxhighlight> will stop reading beyond the 24th character. | ||
+ | |||
+ | Leading blanks in front of numeric types are skipped. | ||
+ | |||
+ | If the source file is not open, the RTE 103 “file not open”, RTE 6 “invalid file handle” (for <syntaxhighlight lang="pascal" inline>input</syntaxhighlight> in a non-[[Mode iso|ISO compiler mode]]) will stop the program. | ||
+ | These RTE may be converted to an {{Doc|package=RTL|unit=sysutils|identifier=einouterror|text=<syntaxhighlight lang="pascal" inline>eInOutError</syntaxhighlight>}} exception if the [[sysutils|<syntaxhighlight lang="pascal" inline>sysUtils</syntaxhighlight> unit]] is included (e. g. via a [[Uses|<syntaxhighlight lang="pascal" inline>uses</syntaxhighlight>-clause]]). | ||
+ | |||
+ | If the source file is open, but no data is available, possibly because the end of file has already been reached, default values for the remaining variables are loaded. | ||
+ | |||
+ | === Interpretation === | ||
+ | |||
+ | <syntaxhighlight lang="pascal" inline>Read</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight> are so powerful, because they interpret given data. | ||
+ | For instance, a <syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight> storing an integer does not expect the binary value to be entered, but their decimal representation with ASCII numerals suffices (e. g. <syntaxhighlight lang="text" inline>42</syntaxhighlight> instead of <syntaxhighlight lang="text" inline>*</syntaxhighlight> [<nowiki></nowiki>[[*#other appearances|asterisk]] has the numeric value 42]). | ||
+ | |||
+ | While <syntaxhighlight lang="pascal" inline>char</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>string</syntaxhighlight> can be stored (sort of) directly, the numeric types <syntaxhighlight lang="pascal" inline>integer</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>real</syntaxhighlight> are converted following certain rules. | ||
+ | The rules are those, you normally write literals of such types within your (Standard) Pascal source code. | ||
+ | However, some compilers’ <syntaxhighlight lang="pascal" inline>read</syntaxhighlight> implementation (here FPC) allow additional formats: | ||
+ | |||
+ | An integer’s hexadecimal base can be indicated by prepending <syntaxhighlight lang="text" inline>0x</syntaxhighlight>, or just <syntaxhighlight lang="text" inline>x</syntaxhighlight> (case insensitive) instead of the usual [[Dollar sign|<syntaxhighlight lang="text" inline>$</syntaxhighlight> (dollar sign)]]. | ||
+ | |||
+ | === Difference between <syntaxhighlight lang="pascal" inline>read</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight> === | ||
+ | |||
+ | <syntaxhighlight lang="pascal" inline>ReadLn</syntaxhighlight> will in contrast to <syntaxhighlight lang="pascal" inline>read</syntaxhighlight> consume a trailing [[End of Line|line feed]]. | ||
+ | It is discarded and does not have any influence on how to save supplied data. | ||
+ | The read line ending is platform-independent. | ||
+ | A line ending typical for Windows-platforms will be read and does not pose a problem, even if the program is run on [[Linux]] or any other platform. | ||
+ | |||
+ | Note, the notion of “line” applies only for <syntaxhighlight lang="pascal" inline>text</syntaxhighlight> files. | ||
+ | Functions like {{Doc|package=RTL|unit=system|identifier=eoln|text=<syntaxhighlight lang="pascal" inline>eoLn</syntaxhighlight>}} and <syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight> only work on such files. | ||
+ | In consequence <syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight> can not be used on typed files (<syntaxhighlight lang="pascal" inline>file of recordType</syntaxhighlight> variables). | ||
+ | |||
+ | == Production usage == | ||
+ | |||
+ | <syntaxhighlight lang="pascal" inline>Read</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight> have a major drawback in that they expect the user to supply data in a given order. | ||
+ | If users do not comply a run-time error will terminate the program. | ||
+ | |||
+ | This is quite unsatisfactory, since a run-time error number won’t enlighten the end user. | ||
+ | You usually want to design your error messages in a way the user is capable in correcting her behavior. | ||
+ | When reading ordinal types one can make use of the [[Val|<syntaxhighlight lang="pascal" inline>val</syntaxhighlight> procedure]]. | ||
+ | |||
+ | <syntaxhighlight lang="pascal" line highlight="19"> | ||
+ | program readNumbers(input, output, stderr); | ||
+ | |||
+ | {$modeSwitch out+} | ||
+ | |||
+ | {** | ||
+ | reads an integer from input | ||
+ | |||
+ | \param destination the variable to store the read value in | ||
+ | \returns true if reading was successful | ||
+ | |||
+ | This function will inform the user about any mistakes. | ||
+ | *} | ||
+ | function readLnInteger(out destination: integer): longbool; | ||
+ | var | ||
+ | /// temporarily stores input string | ||
+ | userInput: ansistring; | ||
+ | /// stores return code of val | ||
+ | errorPosition: valSInt; | ||
+ | begin | ||
+ | readLn(userInput); | ||
+ | |||
+ | val(userInput, destination, errorPosition); | ||
+ | |||
+ | // val is successful, if no character caused problems | ||
+ | readLnInteger := errorPosition = 0; | ||
+ | |||
+ | // tell the user, what went wrong | ||
+ | if not readLnInteger then | ||
+ | begin | ||
+ | if length(userInput) < 1 then | ||
+ | begin | ||
+ | writeLn('Error: There was no input.'); | ||
+ | end | ||
+ | else | ||
+ | begin | ||
+ | writeLn('Error: Could not parse your input as an integer. Your input was:'); | ||
+ | writeLn(userInput); | ||
+ | |||
+ | // set an arrow right below | ||
+ | // the character causing troubles | ||
+ | writeLn(space(errorPosition-1), '⇡'); | ||
+ | writeLn('The character with an arrow underneath caused the troubles.'); | ||
+ | |||
+ | if length(userInput) > bitSizeOf(nativeInt) then | ||
+ | begin | ||
+ | writeLn('Maybe your value is too large.'); | ||
+ | end; | ||
+ | end; | ||
+ | end; | ||
+ | end; | ||
+ | |||
+ | { === M A I N ================================================ } | ||
+ | var | ||
+ | EOI: Boolean; | ||
+ | |||
+ | function endOfInput(): Boolean; | ||
+ | begin | ||
+ | EOI := system.eof(); | ||
+ | endOfInput := EOI; | ||
+ | end; | ||
+ | |||
+ | var | ||
+ | i: integer; | ||
+ | |||
+ | begin | ||
+ | repeat | ||
+ | begin | ||
+ | writeLn('Enter an integer:'); | ||
+ | end | ||
+ | {$push} | ||
+ | {$boolEval off} // lazy evaluation [until or_else is supported] | ||
+ | until endOfInput() or readLnInteger(i) or endOfInput(); | ||
+ | {$pop} | ||
+ | |||
+ | if EOI then | ||
+ | begin | ||
+ | halt(1); | ||
+ | end; | ||
+ | |||
+ | writeLn('Excellent choice!'); | ||
+ | end. | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Beware, it is necessary to check, whether the end of file has been reached ''before'' attempting to read data. | ||
+ | The <syntaxhighlight lang="pascal" inline>text</syntaxhighlight> file <syntaxhighlight lang="pascal" inline>input</syntaxhighlight> may not be open. | ||
+ | Unlike <syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight> ''no'' default value is loaded. | ||
+ | Hence it is imperative to check <syntaxhighlight lang="pascal" inline>val</syntaxhighlight>’s <syntaxhighlight lang="pascal" inline>code</syntaxhighlight> value in order to determine whether the destination variable <syntaxhighlight lang="pascal" inline>v</syntaxhighlight> now has a legit value. | ||
+ | |||
+ | Of course, it would be even better to catch wrong key strokes right when they are made, but this is not possible when utilizing <syntaxhighlight lang="pascal" inline>read</syntaxhighlight> or <syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight>. | ||
+ | |||
+ | {{Note|Therefore the main application of <syntaxhighlight lang="pascal" inline>read</syntaxhighlight> or <syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight> is non-interactive programs reading (generated) data files.}} | ||
+ | |||
+ | Nevertheless, if the convenient interpretation functionality is desired, without having a file open, the procedure {{Doc|package=RTL|unit=system|identifier=readstr|text=<syntaxhighlight lang="pascal" inline>system.readStr</syntaxhighlight>}} can be used to do so. | ||
+ | |||
+ | == See also == | ||
+ | |||
+ | * {{Doc|package=RTL|unit=system|identifier=read|text=<syntaxhighlight lang="pascal" inline>system.read</syntaxhighlight>}} and {{Doc|package=RTL|unit=system|identifier=readln|text=<syntaxhighlight lang="pascal" inline>system.readLn</syntaxhighlight>}} | ||
+ | * [[Why use Pascal#The Readln and Writeln effect|Why use Pascal, § “the <syntaxhighlight lang="pascal" inline>readLn</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>writeLn</syntaxhighlight> effect”]] | ||
+ | * [[Secure programming]] regarding how to properly treat input | ||
+ | * [[Write|<syntaxhighlight lang="pascal" inline>write</syntaxhighlight>]] performing the opposite action | ||
+ | |||
+ | [[Category:Code]] |
Latest revision as of 05:08, 23 August 2020
│
Deutsch (de) │
English (en) │
The procedures read
and readLn
retrieve data from a text
file (such as input
, the command line interface, or any file on disk).
They are defined as part of the Pascal programming language.
Everyone can expect them to work no matter which compiler has been used.
In property
definitions the reserved word read
is used to direct read access.
This article deals with the procedures read
and readLn
.
See object
and related articles for the occurrence of read
in the context of properties.
Behavior
Signature
Read
as well as readLn
share almost the same identical formal signature.
However a formal signature is omitted here, since you can not write their signatures in Pascal.
Therefore a description follows:
As an optional first parameter a text
variable can be specified where data are read from.
Read
is additionally capable of reading from a typed file
variable (file of recordType
).
If no source is specified, input
is assumed.
Thereafter any number of variables can be specified, but at least one has to be present.
They have to be either char
, integer
, real
, or string
.
If you have specified a typed file as the source, all variables have to be of the file’s underlying base type.
Earlier versions of FPC also allowed reading variables of the type PChar
. This has been removed, since no buffer checking is possible with those.
In the case of typed files as source, only variables of the file’s record type can be specified.
Execution
Calling read
/readLn
will place the read (and possibly accordingly interpreted) values to the given variables.
The order of variables matters. For instance, when the following program:
program readDemo(input, output, stderr);
var
i: integer;
c: char;
begin
readLn(i, c);
end.
is supplied with:
42 x
everything is fine.
i
will become 42
and c
will become 'x'
.
But the reverse input order
x 42
will yield a run-time error (in this case RTE 106).
Once data are read and stored, they are “consumed”, thus cannot be retrieved otherwise, but via the variables only.
However, data are read up to the variable’s size limits.
E. g. a fixed length string[24]
will stop reading beyond the 24th character.
Leading blanks in front of numeric types are skipped.
If the source file is not open, the RTE 103 “file not open”, RTE 6 “invalid file handle” (for input
in a non-ISO compiler mode) will stop the program.
These RTE may be converted to an eInOutError
exception if the sysUtils
unit is included (e. g. via a uses
-clause).
If the source file is open, but no data is available, possibly because the end of file has already been reached, default values for the remaining variables are loaded.
Interpretation
Read
and readLn
are so powerful, because they interpret given data.
For instance, a readLn
storing an integer does not expect the binary value to be entered, but their decimal representation with ASCII numerals suffices (e. g. 42
instead of *
[asterisk has the numeric value 42]).
While char
and string
can be stored (sort of) directly, the numeric types integer
and real
are converted following certain rules.
The rules are those, you normally write literals of such types within your (Standard) Pascal source code.
However, some compilers’ read
implementation (here FPC) allow additional formats:
An integer’s hexadecimal base can be indicated by prepending 0x
, or just x
(case insensitive) instead of the usual $
(dollar sign).
Difference between read
and readLn
ReadLn
will in contrast to read
consume a trailing line feed.
It is discarded and does not have any influence on how to save supplied data.
The read line ending is platform-independent.
A line ending typical for Windows-platforms will be read and does not pose a problem, even if the program is run on Linux or any other platform.
Note, the notion of “line” applies only for text
files.
Functions like eoLn
and readLn
only work on such files.
In consequence readLn
can not be used on typed files (file of recordType
variables).
Production usage
Read
and readLn
have a major drawback in that they expect the user to supply data in a given order.
If users do not comply a run-time error will terminate the program.
This is quite unsatisfactory, since a run-time error number won’t enlighten the end user.
You usually want to design your error messages in a way the user is capable in correcting her behavior.
When reading ordinal types one can make use of the val
procedure.
1program readNumbers(input, output, stderr);
2
3{$modeSwitch out+}
4
5{**
6 reads an integer from input
7
8 \param destination the variable to store the read value in
9 \returns true if reading was successful
10
11 This function will inform the user about any mistakes.
12*}
13function readLnInteger(out destination: integer): longbool;
14var
15 /// temporarily stores input string
16 userInput: ansistring;
17 /// stores return code of val
18 errorPosition: valSInt;
19begin
20 readLn(userInput);
21
22 val(userInput, destination, errorPosition);
23
24 // val is successful, if no character caused problems
25 readLnInteger := errorPosition = 0;
26
27 // tell the user, what went wrong
28 if not readLnInteger then
29 begin
30 if length(userInput) < 1 then
31 begin
32 writeLn('Error: There was no input.');
33 end
34 else
35 begin
36 writeLn('Error: Could not parse your input as an integer. Your input was:');
37 writeLn(userInput);
38
39 // set an arrow right below
40 // the character causing troubles
41 writeLn(space(errorPosition-1), '⇡');
42 writeLn('The character with an arrow underneath caused the troubles.');
43
44 if length(userInput) > bitSizeOf(nativeInt) then
45 begin
46 writeLn('Maybe your value is too large.');
47 end;
48 end;
49 end;
50end;
51
52{ === M A I N ================================================ }
53var
54 EOI: Boolean;
55
56function endOfInput(): Boolean;
57begin
58 EOI := system.eof();
59 endOfInput := EOI;
60end;
61
62var
63 i: integer;
64
65begin
66 repeat
67 begin
68 writeLn('Enter an integer:');
69 end
70 {$push}
71 {$boolEval off} // lazy evaluation [until or_else is supported]
72 until endOfInput() or readLnInteger(i) or endOfInput();
73 {$pop}
74
75 if EOI then
76 begin
77 halt(1);
78 end;
79
80 writeLn('Excellent choice!');
81end.
Beware, it is necessary to check, whether the end of file has been reached before attempting to read data.
The text
file input
may not be open.
Unlike readLn
no default value is loaded.
Hence it is imperative to check val
’s code
value in order to determine whether the destination variable v
now has a legit value.
Of course, it would be even better to catch wrong key strokes right when they are made, but this is not possible when utilizing read
or readLn
.
read
or readLn
is non-interactive programs reading (generated) data files.Nevertheless, if the convenient interpretation functionality is desired, without having a file open, the procedure system.readStr
can be used to do so.
See also
system.read
andsystem.readLn
- Why use Pascal, § “the
readLn
andwriteLn
effect” - Secure programming regarding how to properly treat input
write
performing the opposite action