Ada: Adding an exception in a separate procedure when reading a file - file

This is a follow-up of this question: Ada: reading from a file .
I would like to add an exception that checks if the file that I'm opening actually exists or not. I have made a separate procedure to avoid code clutter.
Here is the main code 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 Ada.Text_IO.File_Type; Name : in String) is separate;
begin
Ada.Text_IO.Open (File => Input_File, Mode => Ada.Text_IO.In_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 here is the separate body test_read-open_data.adb of the procedure Open_Data:
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;
On compilation I get an error message in the separate body test_read-open_data.adb:
actual for "File" must be a variable
How to fix this?
Thanks a lot...
Update:
I have now made the following corrections.
In test_read.adb, I now have procedure Open_Data (File : in out Ada.Text_IO.File_Type; Name : in String) is separate;
Updated the definition of the same Open_Data procedure in test_read-open_data.adb.
The program compiles well though I do not see it catch the exception say if I renamed the file fx.txt to fy.txt. The error message I get is just
raised ADA.IO_EXCEPTIONS.NAME_ERROR : fx.txt: No such file or directory
So I do not get my own error message :File not found.
What is still wrong?

The File parameter of Open_Data needs to be an in out parameter (as in, for example, Ada.Text_IO.Create), because you want the opened file to be accessible within Test_Read.
You are getting actual for "File" must be a variable because an in parameter is read-only.
procedure Open_Data (File : in out Ada.Text_IO.File_Type;
Name : in String) is
(Personally I rarely type the in mode, because it’s the default).
But in any case, it looks as though the reason for the observed behaviour is that Test_Read doesn’t actually call Open_Data!
(edited to make the recommended mode in out & to suggest calling Open_Data)

if your goal is to simply check if the file exists, consider using Ada.Directories.Exists

IIRC: Standard_Error is not a file, but a Stream.

I suspect that the reason you are not seeing your error message is that you are using Put rather than Put_Line. Different implementations/platforms treat output to the user's display differently. To be extra sure you will see the message, follow the Put_Line with a Get_Line. The Get_Line generally forces the output of the Put_Line.

Related

Perl Config::IniFiles - how do I create the ini file 'if not exists'? WriteConfig method fails with error

I want to use a number of .ini files to store sets of values to pick up later, when I re-run the script (after a reboot, e.g.). I am trying to write my code such that it will first check to see if the specific .ini file exists, and if so, read in the values, but if not, then create it (the script will subsequently proceed to store values in it).
if (-f '/path/to/file.ini') { # if file exists
# read file into object
my $ini = Config::IniFiles->new(-file => '/path/to/file.ini',
-nomultiline => 1, -fallback => 'parameters', -commentchar => ';'
);
} else {
# create first instance of ini file
WriteConfig('/path/to/file.ini');
}
Obviously I don't understand how to use Config::InFiles because it keeps failing on WriteConfig('/path/to/file.ini');.
Can I create a file with this module, or do I have to do it another way?
WriteConfig is an object method and would be called as $ini->WriteConfig(...);
This creates a new file:
use warnings;
use strict;
use Config::IniFiles;
my $ini = Config::IniFiles->new();
$ini->AddSection('section1');
$ini->newval('section1', 'param1', 123);
$ini->WriteConfig('./file.ini');
File file.ini now contains:
[section1]
param1=123

Why is the extension of my ini files nothing?

I have a procedure to save a file, which is an ini file. The procedure below is just where the user chooses the directory and name of the file:
procedure TForm1.SaveFile(Sender: TObject);
var
Dialog : TSaveDialog;
begin
Dialog := TSaveDialog.Create(self);
try
//dialog properties go here
Dialog.Filter := 'Title (*.ini)|*.ini';
Dialog.Options := Dialog.Options + [ofOverwritePrompt];
if Dialog.Execute then
begin
//any saving procedures go here if required
ShowMessage('File saved: ' + Dialog.FileName);
end
else
ShowMessage('Save file was cancelled');
finally
Dialog.Free;
end;
end;
As you can see I set the filter to ini but no files show at all (it still saves)
The procedure below is where the user can select a previously saved file
procedure TForm1.LoadFileBtnClick(Sender: TObject);
Var
FileName, FileExtension : String;
SelectedFile : TOpenDialog;
begin
SelectedFile := TOpenDialog.Create(nil);
Try
if SelectedFile.Execute() then
FileName := SelectedFile.FileName
else
//Do whatever here if user doesn't select file
Finally
SelectedFile.Free; //Free dialog from memory
End;
FileExtension := ExtractFileExt(FileName);
if not (FileExtension = 'ini') then
exit
else
//Do whatever here if file extension matches specified type
end;
I get the extension of the filename and check if its ini. The ShowMessage is there to see what value is returned for testing purposes. When i click an ini file nothing is returned but when i click a text file '.txt' is returned. Why do my ini files save with the type as 'File' when they are ini files.
How could i change my load file procedure to detect if its an ini file and if not then exit?
Set the property DefaultExt in the SaveDialog to '.ini'
These will solve your problem
I think you are assuming that the fact that you are specifying the SaveDialog's Filter as you do forces the SaveDialog's FileName to have an extension of 'Ini'. It does not. The dialog's Filter property determines what files are listed in it, not the extension that the saved file has.
Try the following code:
if SaveDialog.Execute then
begin
SaveSeatingPlan(SaveDialog.FileName);
Assert(SameText(ExtractFileExt(SaveDialog.FileName), '.Ini'));
ShowMessage('File saved: ' + SaveDialog.FileName);
end else
ShowMessage('Save file was cancelled');
Instead of the Assert, you can of course append the '.Ini' extension in your code or, better, do what the other answer suggests.

Call dbms_comparison Oracle package from function

I am posting this question as I am facing some errors when trying to use the dbms_comparison oracle package from an Oracle function.
I created a function which should return the scanID of the performed comparison to be able to retrieve the scanID's value from Java. However, the function is not being successfully executed as it is raising some errors. The dbms_comparison is being recognized as an identifier and therefore it is raising the following error: PLS-00201: identifier 'DBMS_COMPARISON' must be declared.
Please find below the Oracle function I created. Any help would be appreciated.
CREATE OR REPLACE FUNCTION compareRecords
RETURN NUMBER IS
scanID number;
v_scan_info dbms_comparison.comparison_type;
v_compare_result boolean;
begin
v_compare_result:= dbms_comparison.compare(
comparison_name => 'synchronised',
scan_info => v_scan_info,
perform_row_dif => TRUE);
dbms_output.put_line('Scan id: '||v_scan_info.scan_id);
scanID := v_scan_info.scan_id;
if v_compare_result = TRUE then
dbms_output.put_line(a => 'Tables are synchronized!');
else
dbms_output.put_line(a => 'Warning! Data divergence found!'||chr(10));
end if;
RETURN scanID;
end compareRecords;
I tested your code as sys and was compiled successfully. As another user failed with
PLS-00201: identifier 'DBMS_COMPARISON' must be declared.
So you have to add on your code sys. to dbms_comparison and need to grant execute on sys.dbms_comparison to youruser

Unable to open a file with uigetfile in Matlab

I am building a code that lets the user open some files.
reference = warndlg('Choose the files for analysis.');
uiwait(reference);
filenames2 = uigetfile('./*.txt','MultiSelect', 'on');
if ~iscell(filenames2)
filenames2 = {filenames2}; % force it to be a cell array of strings
end
numberOfFiles = numel(filenames2);
data = importdata(filenames2{i},delimiterIn,headerlinesIn);
When I run the code, the prompts show up, I press OK, and then nothing happens. The code just stops, telling me :
Error using importdata (line 137)
Unable to open file.
Error in FreqVSChampB_no_spec (line 119)
data=importdata(filenames2{1},delimiterIn,headerlinesIn);
I just don't have the opportunity to select a file. The cellarray stays empty as showed in the following image.
MATLAB can't find the file that you have selected. Your variable filenames2 contains only the name of the file, not its full path. If you don't provide the full path to importdata, it will search for whatever file name you provide on the MATLAB path, and if it can't find it it will error as you see.
Try something like this - I'm just doing it with single selection for ease of description, but you can do something similar with multiple selection.
[fileName, pathName] = uigetfile('*.txt');
fullNameWithPath = fullfile(pathName, fileName);
importdata(fullNameWithPath)
fullfile is useful, as it inserts the correct character between pathName and fileName (\ on Windows, / on Unix).
You can try to add
pause(0.1);
just after uiwait(reference);
For me it works. In fact I've noticed the active windows changes when we use uiwait and uigetfile.

Append file operation in Ada

I'm very new to Ada and one thing that I find hard to grasp is working with Files in Ada when it comes to append some values in a file. It seems easier for me to do so in C. Anyway, I haven't found good information and I hope someone could help me here.
I declare the following first:
PACKAGE Seq_Float_IO IS NEW Ada.Sequential_IO (Element_Type => Long_Float);
Flo_File : Seq_Long_Float_IO.File_Type;
and then I create a file "bvalues.dat":
Seq_Long_Float_IO.Create(File => Flo_File, Name => "bvalues.dat");
and then to write say a variable named "Largest", I use:
Seq_Long_Float_IO.Write(File => Flo_File, Item => Largest);
I see that every time I run the code the file "bvalues.dat" gets destroyed and new values are written to it as the program runs. This is ok for me. What I'm doing in my code is to find the largest value of some values and store the largest element in the file "bvalues.dat".
Now say I have to repeat the operation with different sets of values IN THE SAME PROGRAM (say with an outer LOOP) and I need to store the largest element of each set of values. Thus I need to be able to append each largest value of every set to the file "bvalues.dat". How to achieve this?
Do I need to close the file "bvalues.dat" each time after writing a largest value and then open it again:
Seq_Long_Float_IO.Open(File => Flo_File, Mode => Append_File, Name => "bvalues.dat");
say after an index in an outer loop gets incremented to take in the next set of values for which the largest element is to be computed and then write as I did above
Seq_Long_Float_IO.Write(File => Flo_File, Item => Largest); ?
NEW INFO:
I get the error:
40. Seq_Long_Float_IO.Open(File => Flo_File, Mode => Append_File, Name => "bvalues.dat");
|
>>> "Append_File" is not visible
>>> non-visible declaration at a-sequio.ads:58, instance at line 8
>>> non-visible declaration at a-textio.ads:56
Thanks a lot...
Test file:
WITH Ada.Text_IO;
WITH Ada.Sequential_IO;
PROCEDURE TestWrite5 IS
PACKAGE Seq_Float_IO IS NEW Ada.Sequential_IO (Element_Type => Float);
Flo_File : Seq_Float_IO.File_Type;
BEGIN
Seq_Float_IO.Open (File => Flo_File, Mode => Seq_Float_IO.Append_File,
Name =>"bvalues.dat");
exception
when Name_Error =>
Create (File => Flo_File, Mode => Out_File, Name => "bvalues.dat");
END TestWrite5;
On compiling I get:
exception
when Name_Error =>
|
"Name_Error" is not visible
non-visible declaration at a-sequio.ads:111, instance at line 5
non-visible declaration at a-textio.ads:298
non-visible declaration at a-ioexce.ads:23
Create (File => Flo_File, Mode => Out_File, Name => "bvalues.dat");
|
"Create" is not visible
non-visible declaration at a-sequio.ads:73, instance at line 5
non-visible declaration at a-textio.ads:90
15.
It doesn't change if I also put Seq_Float_IO.Out_File instead of just Out_File.
Create, like the name implies, will create a brand new file, even if one already exists.
If the file already exists and you want to append to it, you would use Open.
If you want to open it for appending, but if it doesn't exist create it, the normal idiom is to put the Create call in an exception handler around Open, like so:
begin
Open (File => Flo_File, Mode => Append_File, Name => "bvalues.dat");
exception
when Name_Error =>
Create (File => Flo_File, Mode => Out_File, Name => "bvalues.dat");
end;
From the rest of your text, it looks like you are thinking about storing temp values in a file. I wouldn't do that unless you need persistence for some reason (recovering from crashes, etc). Disk IO is way way way slow. Just keep your temp values in a variable and save the result when you have it.

Resources