I/O Operations in Eiffel
Learn console output, keyboard input, and text file reading and writing in Eiffel using io and PLAIN_TEXT_FILE with Docker-ready examples
Input and output are how a program talks to the outside world - the console, the keyboard, and files on disk. In Hello World you already saw print and io.put_string. This tutorial goes further: reading what a user types, writing structured output, and creating and reading text files.
As a pure object-oriented language, Eiffel does not have free-standing I/O functions. Instead, I/O is provided through objects. The feature io (inherited by every class from ANY) is an object of type STD_FILES that represents the standard input, output, and error streams. Files are represented by the PLAIN_TEXT_FILE class from the base library. You send messages to these objects - put_string, read_line, close - rather than calling global functions.
Eiffel also keeps to its Command-Query Separation principle here. A read operation such as io.read_line is a command: it changes the state of the stream and stores what it read in a query like io.last_string. You read the result afterward instead of getting it back directly from the call. This pattern - “do the read, then ask for the last value” - is the single most important thing to understand about Eiffel I/O.
By the end of this tutorial you will be able to print formatted output to the console, prompt for and read keyboard input, and write and read back a text file.
Console Output
You have several ways to write to the console. print (from ANY) takes any object and outputs its string form. The io object offers typed routines like put_string, put_integer, and put_new_line. To turn a non-string value into text explicitly, call .out on it.
Create a file named io_operations.e:
note
description: "Demonstrates console and file I/O in Eiffel"
class
IO_OPERATIONS
create
make
feature -- Initialization
make
-- Run all I/O demonstrations in order.
do
show_console_output
write_to_file
read_from_file
end
feature -- Console output
show_console_output
-- Demonstrate several forms of console output.
local
count: INTEGER
do
count := 42
-- print comes from ANY and accepts any object
print ("=== Console Output ===%N")
-- io.put_string writes a string with no trailing newline
io.put_string ("A plain string%N")
-- Typed output: write an integer directly
io.put_string ("Count is: ")
io.put_integer (count)
io.put_new_line
-- Convert a value to a string with .out and concatenate
io.put_string ("Doubled: " + (count * 2).out + "%N")
-- %T is a tab; %N is a newline
io.put_string ("Tab%Tseparated%Tvalues%N")
end
feature -- File output
write_to_file
-- Create notes.txt and write several lines to it.
local
output_file: PLAIN_TEXT_FILE
do
create output_file.make_open_write ("notes.txt")
output_file.put_string ("First line%N")
output_file.put_string ("Second line%N")
output_file.put_string ("Number: ")
output_file.put_integer (100)
output_file.put_new_line
output_file.close
print ("%N=== Wrote notes.txt ===%N")
end
feature -- File input
read_from_file
-- Read notes.txt back and echo each line to the console.
local
input_file: PLAIN_TEXT_FILE
do
print ("=== Reading notes.txt ===%N")
create input_file.make_open_read ("notes.txt")
from
input_file.read_line
until
input_file.exhausted
loop
print (input_file.last_string + "%N")
input_file.read_line
end
input_file.close
end
end
This single class covers three concepts. show_console_output demonstrates the different output routines. write_to_file creates a file and writes to it. read_from_file opens the same file and prints its contents.
Writing to a File
create output_file.make_open_write ("notes.txt") creates a PLAIN_TEXT_FILE object and opens the file for writing, truncating it if it already exists. A file object understands the same put_string, put_integer, and put_new_line messages as io - because both STD_FILES and PLAIN_TEXT_FILE inherit them from the same file abstraction. Always close the file when you are done so buffered data is flushed to disk.
Reading from a File
create input_file.make_open_read ("notes.txt") opens the file for reading. The loop shows the Command-Query pattern in action:
read_lineis the command - it reads the next line intolast_string.last_stringis the query - it holds the text that was just read (without the newline).exhaustedbecomesTrueonce a read attempt reaches end-of-file with nothing left.
The from ... until ... loop ... end form is Eiffel’s loop. We prime the loop with one read_line before it starts, print inside the body, then read again at the bottom - a standard read-ahead pattern.
Reading Keyboard Input
Console input follows the same command-then-query rhythm. io.read_line reads a full line into io.last_string; io.read_integer reads a number into io.last_integer.
Create a file named input_demo.e:
note
description: "Reading input from the keyboard"
class
INPUT_DEMO
create
make
feature -- Initialization
make
-- Prompt for a name and an age, then respond.
local
age: INTEGER
do
io.put_string ("What is your name? ")
io.read_line
io.put_string ("Hello, " + io.last_string + "!%N")
io.put_string ("How old are you? ")
io.read_integer
age := io.last_integer
io.put_string ("Next year you will be ")
io.put_integer (age + 1)
io.put_new_line
end
end
Because this program waits for the user to type, it is interactive. Here is a sample session, where the lines after each prompt are what the user typed:
What is your name? Ada
Hello, Ada!
How old are you? 30
Next year you will be 31
Notice again that neither read_line nor read_integer returns the value directly. You call the command, then read io.last_string or io.last_integer. This is Command-Query Separation applied consistently: commands change state, queries report it.
The Configuration File
Eiffel compiles a whole system, not a single file, so the compiler needs an ECF (Eiffel Configuration File) that names the root class and its creation feature. The io_operations.ecf below points the root at IO_OPERATIONS and its make feature, and pulls in the base library for STRING, INTEGER, PLAIN_TEXT_FILE, and the io object.
Create a file named io_operations.ecf:
| |
The <cluster> element with location="." tells the compiler to look in the current directory for source files, so it will find io_operations.e.
Running with Docker
With io_operations.e and io_operations.ecf in the current directory, compile and run the program:
| |
The compiler generates C from your Eiffel code, compiles it, and places the executable in EIFGENs/io_operations/W_code/. Running it produces the console output, writes notes.txt into your mounted directory, and reads that file back.
Expected Output
=== Console Output ===
A plain string
Count is: 42
Doubled: 84
Tab separated values
=== Wrote notes.txt ===
=== Reading notes.txt ===
First line
Second line
Number: 100
After the run, a new file notes.txt appears in your directory containing:
First line
Second line
Number: 100
Key Concepts
- I/O is object-oriented - there are no global I/O functions. You send messages to the
ioobject (of typeSTD_FILES) and toPLAIN_TEXT_FILEobjects. - Command-Query Separation governs input - a read is a command (
read_line,read_integer); you retrieve the result from a query afterward (last_string,last_integer). Reads never return the value directly. iois inherited fromANY- every class can useio.put_string,io.put_integer,io.put_new_line,io.read_line, andio.read_integerwithout any import.- Files share the same interface as the console -
put_string,put_integer, andput_new_linework identically onioand on aPLAIN_TEXT_FILE, because both inherit from the same file abstraction. - Open with an intent -
make_open_writecreates (and truncates) a file for writing;make_open_readopens it for reading. Alwaysclosea file when finished. - Read files with a read-ahead loop - prime with one
read_line, loopuntil exhausted, and read again at the bottom solast_stringalways holds a real line. - Escapes use
%-%Nis newline and%Tis tab, not the C-style\nand\t. - Convert values with
.out- any object’soutquery gives a string representation you can concatenate or print.
Running Today
All examples can be run using Docker:
docker pull eiffel/eiffel:latest
Comments
Loading comments...
Leave a Comment