Ada: throwing wrong exception when opening a non-e

2019-08-28 17:12发布

问题:

This is a follow up of this [post] Ada: Adding an exception in a separate procedure when reading a file

When my code below opens a file that doesn't exist, instead of throwing a ADA.IO_EXCEPTIONS.NAME_ERROR, it is throwing a ADA.IO_EXCEPTIONS.STATUS_ERROR.

Below are the codes.

Main file: test_read.adb:

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Long_Float_Text_IO;
with Ada.Float_Text_IO;


procedure Test_Read is

   Input_File    : File_Type;
   value         : Long_Float;

   procedure Open_Data (File : in out  Ada.Text_IO.File_Type; Name : in String) is separate;

begin

   Open_Data (File => Input_File, Name => "fx.txt");

   while not End_Of_File (Input_File) loop
      Ada.Long_Float_Text_IO.Get (File => Input_File, Item => value);
      Ada.Long_Float_Text_IO.Put (Item => value, Fore => 3, Aft  => 5, Exp  => 0);
   Ada.Text_IO.New_Line;
   end loop;
    Ada.Text_IO.Close (File => Input_File);

end Test_Read;

And the separate procedure body test_read-open_data.adb:

separate (test_read)

procedure Open_Data (File : in out  Ada.Text_IO.File_Type;
                 Name : in String) is

   --this procedure prepares a file for reading
   begin
      begin
         Ada.Text_IO.Open
           (File => File,
            Mode => Ada.Text_IO.In_File,
            Name => Name);
      exception
         when Ada.Text_IO.Name_Error =>
         Ada.Text_IO.Put(File => Standard_Error, Item => "****File not found....****");
   end;
end Open_Data;

The error message that is thrown:

****File not found....****

Execution terminated by unhandled exception
Exception name: ADA.IO_EXCEPTIONS.STATUS_ERROR
Message: file not open
Call stack traceback locations:
0x40bf0f 0x40ead0 0x424b08 0x424e4a 0x4010b4 0x401146 0x7c817075
[2012-03-21 13:45:44] process exited with status 1 (elapsed time: 00.13s)

I have tried a few things:

  1. Put with Ada.IO_Exceptions; in test_read.adb and put when Ada.IO_Exceptions.Name_Error => instead of when Ada.Text_IO.Name_Error => in test_read-open_data.adb. But there is no change.

  2. In test_read-open_data.adb, I changed the line Mode => Ada.Text_IO.In_File to make it become Mode => Ada.Text_IO.Out_File as shown below:

    Ada.Text_IO.Open (File => File, Mode => Ada.Text_IO.Out_File, Name => Name);

But there is no improvement.

So how to get the right ADA.IO_EXCEPTIONS.NAME_ERROR?

A related question:

What's the difference between Ada.Text_IO.Name_Error and ADA.IO_EXCEPTIONS.NAME_ERROR? In my program I want to be informed when the file of name fx.txt does not exist. Which one of these two exceptions is appropriate?

Thanks a lot

UPDATE (Latest Codes)

Here are my updated codes:

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Long_Float_Text_IO;
with Ada.Float_Text_IO;


procedure Test_Read is

   Input_File    : File_Type;
   value         : Long_Float;
   Success       : Boolean;

procedure Open_Data (File : in out  Ada.Text_IO.File_Type; Name : in String; Success : out Boolean) is separate;

begin

   Open_Data (File => Input_File, Name => "fx.txt", Success => Success);
   if not Success then
      return;
   end if;

   while not End_Of_File (Input_File) loop
      Ada.Long_Float_Text_IO.Get (File => Input_File, Item => value);
      Ada.Long_Float_Text_IO.Put (Item => value, Fore => 3, Aft  => 5, Exp  => 0);
      Ada.Text_IO.New_Line;
   end loop;
   Ada.Text_IO.Close (File => Input_File);
   Ada.Text_IO.Put_Line (Item => "Reading file success: " & Boolean'Image (Success));

end Test_Read;

and the separate procedure:

separate (test_read)

procedure Open_Data (File : in out  Ada.Text_IO.File_Type;
                 Name : in String; Success : out Boolean) is

   --this procedure prepares a file for reading
     begin
      Success := True;
      begin
         Ada.Text_IO.Open
           (File => File,
            Mode => Ada.Text_IO.Out_File,
            Name => Name);
      exception
         when Ada.Text_IO.Name_Error  =>
         Success := False;   
         Ada.Text_IO.Put (File => Standard_Error, Item => "****File not found....****");
      end;
end Open_Data;

On compiling with file fx.txt present, I get:

Execution terminated by unhandled exception
Exception name: ADA.IO_EXCEPTIONS.MODE_ERROR
Message: file not readable
Call stack traceback locations:
0x40bf2b 0x40ead0 0x424b58 0x424f5a 0x4010b4 0x401146 0x7c817075
[2012-03-22 08:39:39] process exited with status 1 (elapsed time: 00.14s)

And the contents of the file fx.txt **get erased and its contents are not displayed on running the program**

On compiling with file fx.txt renamed to fy.txt, I get:

****File not found....****
[2012-03-22 08:45:31] process terminated successfully (elapsed time: 00.13s)

So what went wrong?

回答1:

The output is just what I would expect: a Name_Error is thrown and caught, File not found is printed, and the program continues. Open_Data does not tell its caller that the file has not been opened, and the subsequent operations on the file trigger a Status_Error. You could, for example, add a Success : out Boolean to Open_Data's parameters, or raise an exception (one of your own, or simply re-raise Name_Error.

E.g.

Open_Data (File => Input_File, Name => "fx.txt", Success => Success);
if not Success then
   return;
end if;

while not End_Of_File (Input_File) loop


回答2:

I'm answering to the updated content of your post.

The content of your file is being deleted because you picked a wrong File_Mode. Judging by the rest of your code your intention was to read from the file but you specified Ada.Text_IO.Out_File as the operation mode which specifies that the file will be used for writing.

Out_File will also discard the current contents of the file. If you intend to write to the file later on specify Inout_File as the mode or Append_File if your intention is only to append new content to the file without reading or removing the existing content.

As for the ADA.IO_EXCEPTIONS.MODE_ERROR exception being raised. You asked to read from a file handle opened in write only mode (Out_File) - this is a clear error and results in the exception being raised.

In summary. Change the Mode in the call to Ada.Text_IO.Open from Ada.Text_IO.Out_File to Ada.Text_IO.In_File.