7. File Access

Introduction

------------------------------------------------------------------------------
-- Normal textual input and output is accomplished using the pacakge
-- Ada.Text_IO. The following I/O routines are taken from that package

file : File_Type;

begin
   Open(File => file, Name => "/usr/local/widgets/data", Mode => In_File);
exception
   when Name_Error =>
      Put(File => Standard_Error, Item => "File name not found.");
   when Status_Error =>
      Put(File => Standard_Error, Item => "File already open.");
   when Use_Error =>
      Put(File => Standard_Error,
          Item => "You do not have permission to open the file");
end;
-------------------------------
file : File_Type;
length : Natural;
line   : String(1..1024); -- some string large enough to hold any line in
                          -- the file
begin
   Open(File => file, Name => "/usr/local/widgets/data", Mode => In_File);
   while not End_Of_File(file) loop
      Get_Line(File => file, Item => line, Last => length);
      Put_Line(Item => line(1..length)); -- writes to stdout
   end loop;
   Close(file);
exception
   when Name_Error =>
      Put(File => Standard_Error, Item => "File name not found.");
   when Status_Error =>
      Put(File => Standard_Error, Item => "File already open.");
   when Use_Error =>
      Put(File => Standard_Error,  -- writes to stderr
          Item => "You do not have permission to open the file");
end;
-------------------------------
num : float;

while not End_Of_File loop
   begin
      Get(Item => num); -- read a float from stdin
      Put_Line(float'Image(num)); -- write to stdout
   exception
      when Data_Error =.
         Put(File => Standard_Error, -- write to stderr
             Item => "File contains non-numeric data");
         Skip_Line; -- skip the rest of the current input line
   end;
end loop;
-------------------------------
logfile : File_Type;

begin
   Open(File => logfile,
        Name => "/tmp/log",
        Mode => Out_File);  -- open for output
exception
   when Name_Error =>
      Put(File => Standard_Error, Item => "File name not found.");
   when Status_Error =>
      Put(File => Standard_Error, Item => "File already open.");
   when Use_Error =>
      Put(File => Standard_Error,  -- writes to stderr
          Item => "You do not have permission to open the file");
end;
-------------------------------
oldfile : File_Type;

oldfile := Current_Output; -- save old file handle
Set_Output(logfile); -- switch standard output
Put_Line("Countdown initiated ...");
Set_Output(oldfile); -- return to original output
Put_Line("You have 30 seconds to reach maximum safety distance.");
------------------------------------------------------------------------------

Opening a File

------------------------------------------------------------------------------
source : file_type;
sink   : file_type;

-- open file for reading
begin
   Open(File => source, Name => path, Mode => In_File);
exception
   when Name_Error =>
      Put(File => Standard_Error, Item => "File name not found.");
   when Status_Error =>
      Put(File => Standard_Error, Item => "File already open.");
   when Use_Error =>
      Put(File => Standard_Error,
          Item => "You do not have permission to open the file");
end;

-- open file for writing
begin
   Open(File => sink, Name => path, Mode => Out_File);
exception
   when Name_Error =>
      Put(File => Standard_Error, Item => "File name not found.");
   when Status_Error =>
      Put(File => Standard_Error, Item => "File already open.");
   when Use_Error =>
      Put(File => Standard_Error,
          Item => "You do not have permission to open the file");
end;

-- Open file for writing, creating a new file
begin
   Create(File => sink, Name => path);
exception
   when Name_Error =>
      Put(File => Standard_Error, Item => "File name not found.");
   when Status_Error =>
      Put(File => Standard_Error, Item => "File already open.");
   when Use_Error =>
      Put(File => Standard_Error,
          Item => "You do not have permission to open the file");
end;
-------------------------------
-- You must instantiate the package Ada.Direct_Io to perform both input
-- and output on a file.
package dir_text is new Ada.Direct_Io(Character);
use dir_text;

direct : File_Type;

begin
   Open(File => direct, Name => path, Mode => InOut_File);
exception
   when Name_Error =>
      Put(File => Standard_Error, Item => "File name not found.");
   when Status_Error =>
      Put(File => Standard_Error, Item => "File already open.");
   when Use_Error =>
      Put(File => Standard_Error,
          Item => "You do not have permission to open the file");
end;
-------------------------------
sink : File_Type;

begin
   Open(File => sink, Name => path, Mode => Append_File);
exception
   when Name_Error =>
      Put(File => Standard_Error, Item => "File name not found.");
   when Status_Error =>
      Put(File => Standard_Error, Item => "File already open.");
   when Use_Error =>
      Put(File => Standard_Error,
          Item => "You do not have permission to open the file");
end;
------------------------------------------------------------------------------

Opening Files with Unusual Filenames

------------------------------------------------------------------------------
-- Ada does not provide any rules about file names. Unusual file names are
-- opened the same as common file names.
------------------------------------------------------------------------------

Expanding Tildes in Filenames

------------------------------------------------------------------------------
-- Ada provides no facilities for expanding tildes in file names.
------------------------------------------------------------------------------

Making Perl Report Filenames in Errors

------------------------------------------------------------------------------
-- (The Ada equivalent)
sink : File_Type;

begin
   Open(File => sink, Name => path, Mode => Append_File);
exception
   when Name_Error =>
      Put(File => Standard_Error, Item => "File " & path " not found.");
   when Status_Error =>
      Put(File => Standard_Error, Item => "File " & path & " already open.");
   when Use_Error =>
      Put(File => Standard_Error,
          Item => "You do not have permission to open file " & path);
end;
------------------------------------------------------------------------------

Creating Temporary Files

------------------------------------------------------------------------------
-- Passing in a null string for the file name creates a temporary file

begin
   Create(File => sink, Name => "");
exception
   when Use_Error =>
      Put(File => Standard_Error,
          Item => "You do not have permission to open the file");
end;
------------------------------------------------------------------------------

Storing Files Inside Your Program Text

------------------------------------------------------------------------------
-- Not allowed in Ada.
------------------------------------------------------------------------------

Writing a Filter

------------------------------------------------------------------------------
line : String(1..256);
length : Natural;

while not End_Of_File loop
   Get_Line(Item => line, Last => length);
   -- ...  -- do something with the input line
end loop;
-------------------------------
-- The GNAT extension package Gnat.Command_Line provides some high level
-- command line parsing capabilities.
-- Simple command line parsing is provided by the standard package
-- Ada.Command_Line.

source : File_Type;
for argnum in 1..Argument_Count loop
   begin
      Open(File => Source, Name => Argument(argnum),
           Mode => In_File);
      while not End_Of_File(source) loop
         -- process the file from the command line
      end loop;
   exception
      when Name_Error =>
         Put(File => Standard_Error, Item => "File name not found.");
      when Status_Error =>
         Put(File => Standard_Error, Item => "File already open.");
      when Use_Error =>
         Put(File => Standard_Error,
             Item => "You do not have permission to open the file");
   end;
end loop;
-------------------------------
-- arg demo 1: Process optional -c flag
loop
   case GetOpt("-c") is
      when ASCII.NUL =>
         exit; -- exit loop
      when 'c' =>
         -- set whatever internal flag corresponds to the "-c" option
      when Others =>
         raise Program_Error; -- cannot occur!
   end case;
end loop;
-------------------------------
-- arg demo 2: Process optional -NUMBER flag
loop
   case GetOpt("1 2 3 4 5 6 7 8 9") is
      when ASCII.NUL =>
         exit;
      when '1' =>
         -- process 1
      when '2' =>
         -- process 2
      when '3' =>
         -- process 3
      when '4' =>
         -- process 4
      when '5' =>
         -- process 5
      when '6' =>
         -- process 6
      when '7' =>
         -- process 7
      when '8' =>
         -- process 8
      when '9' =>
         -- process 9
      when Others =>
         raise Program_Error;
   end case;
end loop;
-------------------------------
-- arg demo 3: Process clustering -a, -i, -n, or -u flags

loop
   case Get_Opt("a i n u") is
      when ASCII.NUL =>
         exit;
      when 'a' =>
         append := true;
      when 'i' =>
         ignore_ints := true;
      when 'n' =>
         nostdout := true;
      when 'u' =>
         unbuffer := true;
      when Others =>
         raise Program_Error;
   end case;
end loop;
------------------------------------------------------------------------------

Modifying a File in Place with Temporary File

------------------------------------------------------------------------------
-- Ada has no "rename" built in. It can, however, call existing programs
-- to achieve the same purpose.
with Interfaces.C; use Interfaces.C;
procedure Rename_File(From, To : String) is
   function system(Command : Char_Array) return Int;
   pragma Import(C, system, "system");
   rc : Int;
begin
   rc := system(To_C("mv " & From & " " & To));
end Rename_File;
-------------------------------
Open(File => Old, Name => old_file, Mode => In_File);
Create(File => New, Name => new_file);
while not End_Of_File(Old) loop
   Get_Line(File => Old, Item => Line, Last => Length);
   -- process the data in Line
   Put_Line(File => New, Item => Line(1..Length));
end loop;
Close(Old);
Close(New);
Rename_File(old_file, old_file & ".orig");
Rename_File(new_file, old_file);
------------------------------------------------------------------------------

Modifying a File in Place with -i Switch

Modifying a File in Place Without a Temporary File

Locking a File

Flushing Output

Reading from Many Filehandles Without Blocking

Doing Non-Blocking I/O

Determining the Number of Bytes to Read

Storing Filehandles in Variables

Caching Open Output Filehandles

Printing to Many Filehandles Simultaneously

Opening and Closing File Descriptors by Number

Copying Filehandles

Program: netlock

Program: lockarea