More About Ada.Text_IO
We're almost ready for Outside Assignment 5. For that assignment, we had to cover type Text, access types, and exceptions. We also need to learn a little more about Ada.Text_IO before we do the assignment.
Ada.Text_IO does I/O with text files and the terminal. Text files are files that can be listed at the terminal. (Binary files are handled with other packages to be discussed in the Advanced Topics section, such as Ada.Direct_IO and Ada.Sequential_IO.)
The full specification of Ada.Text_IO is in Annex A.10.1 of the Ada 95 RM. It's rather long, and some of the procedures and functions are rarely used. So there's a simplified specification of Ada.Text_IO in your printed course notes, starting on page 17. Please consult your printed course notes during the following discussion.
Note that there's a limited private type called File_Type. For each file that our program will use, we must create an object of this type, for example, F1, F2 : File_Type;. We can then use these objects in the procedures Create and Open, to associate file names with the objects of type File_Type.
Note that the I/O procedures, such as New_Line, Put, and Get, have one version for use with the terminal, and another version for use with a file. The file version takes an object of type File_Type, not the name of the file. The file must first have been Created or Opened.
The exception Status_Error is raised by trying to do I/O on a closed file. Mode_Error is raised by trying to read from a file opened or created with mode Out_File, or by trying to write to a file of mode In_File. Name_Error is raised by trying to Open a file that doesn't exist, or by trying to Create a file with a name not allowed by the system. End_Error is raised by trying to read past an end-of-file.
New_Line creates one or more blank lines on output, and Skip_Line skips one or more lines of input. We can Put characters and strings, and we can Put_Line a string. We can Get a character, and Get_Line a string. Note that when we Get_Line a string, the procedure returns the number of characters that were in the line. Thus, if we have S : String(1 .. 80); Len : Integer; and we execute Get_Line(S, Len); and the user types Hello followed by CR, Len will be set to 5, S(1 .. 5) will be set to "Hello", and the rest of S will be unmodified.
Ada.Text_IO.Integer_IO can be instantiated for any integer type, including user-defined types and derived types like Counter and No_Of_Apples.
When we call Put in an instantiation of Integer_IO (or in Ada.Integer_Text_IO), we can optionally specify the width and the base.
The generic package Ada.Text_IO.Float_IO can be instantiated for any floating point type, such as Float (equivalent to Ada.Float_Text_IO) and the user-defined type Real that we created earlier. Put allows us optionally to specify the number of places before and after the decimal point, and the size of the optional exponent field.
The generic package Ada.Text_IO.Enumeration_IO can be instantiated for any enumeration type. Put allows us optionally to specify the width.
Ada.Text_IO contains another generic package Fixed_IO for fixed point types, not shown in our simplified version. Fixed point types will be discussed in the section on More Records and Types.
To illustrate the use of Ada.Text_IO, here's a simple program that prompts for the names of an old input file and a new output file, and copies the input file to the output. It's assumed that the input file is a plain text file no wider than 80 characters, and that it contains no special control characters such as form feeds. This program also appears on page 19 of your printed course notes:
-- For Ada 83, say simply Text_IO. with Ada.Text_IO; use Ada.Text_IO; procedure Filecopy is F1, F2 : File_Type; S : String(1 .. 80); Len : Integer; begin Put("Input file: "); Get_Line(S, Len); Open(File => F1, Mode => In_File, Name => S(1 .. Len)); Put("Output file: "); Get_Line(S, Len); Create(File => F2, Mode => Out_File, Name => S(1 .. Len)); while not End_Of_File(F1) loop Get_Line(F1, S, Len); Put_Line(F2, S(1 .. Len)); end loop; Close(F1); Close(F2); end Filecopy;
In many systems, all files are closed automatically when the main program terminates, and this program would work even without Close(F1); and Close(F2);
There's no way to test whether a file already exists without trying to Open it and trapping the Name_Error if the file doesn't exist. The following function determines whether a file name represents an existing file. It also appears on page 19 of your printed course notes:
-- For Ada 83, say simply Text_IO. with Ada.Text_IO; use Ada.Text_IO; function Exists(File_Name : in String) return Boolean is F : File_Type; Answer : Boolean := True; begin begin Open(F, In_File, File_Name); Close(F); exception when Name_Error => Answer := False; end; return Answer; end Exists;
QuestionWhich exception is raised by attempting to do I/O on a closed file?
You're right! Status_Error is raised by an attempt to do I/O on a closed file.
No, Mode_Error is raised by an attempt to read from a file of mode Out_File, or write to a file of mode In_File.
No, Name_Error is raised by an attempt to Open a file that doesn't exist, or Create a file with an illegal name.
No, End_Error is raised by an attempt to read past an end-of-file.