File IO in ada, how to write Strings to file?
I have some problem regarding writing String variable to a file. The problem is that I have to specify the exact lengt开发者_C百科h of that String. Or else the output file will just contain some scrap values. I wonder if this can be solved somehow without the need to tell the length of the String before hand?
I know that my Get()
procedure stores the Length of that variable, and I just could return it to the main program. However I want to write my program so it will do all the read from the input file first before I begin writing to the out file.
with Ada.Text_Io, Ada.Integer_Text_Io;
use Ada.Text_Io,Ada.Integer_Text_Io;
procedure Uppgift is
type Bil_Register is
record
Namn : String(1..50);
Adress : String(1..50);
Post : String(1..50);
Reg : String(1..6);
end record;
Infil : File_Type;
Utfil : File_Type;
L, I : Integer;
Br : Bil_Register;
procedure Get(F : in out File_Type; Br : out Bil_Register) is
Length : Integer;
begin
Get_Line(F, Br.Namn, Length);
end;
begin
Open(Infil, In_File, "register.txt");
Create(Utfil, Out_File, "test.txt");
Get(Infil, Br);
Put_Line(Utfil, Br.Namn);
Close(Infil);
Close(Utfil);
end Uppgift;
-
EDIT (2011.08.20)
This seems to be an issue with Unix based OS only. When using Windows you don't have to be absolute with string size when you print it out to file or screen
Well, the length of the valid part of a string has to be tracked somewhere.
You could maintain the valid length of each of your record's string fields as a separate field:
Namn : String (1..50);
Namn_Length : Natural;
You could define your own variable string type package, or use a pre-existing one such as Variable_Length. E.g.
Namn : Variable_Length.Variable_String(50);
You could use Unbounded_String for the fields and variables:
Namn : Unbounded_String;
And Ada.Text_IO.Unbounded_IO for I/O:
with Ada.Strings.Unbounded;
use Ada.Strings.Unbounded;
with Ada.Text_IO.Unbounded_IO;
procedure UTIO_Demo is
use Ada.Text_IO;
F : Ada.Text_IO.File_Type;
Data : Unbounded_String := To_Unbounded_String("Output by Unbounded_IO");
begin
Create(F, Ada.Text_IO.Out_File, "utio.tst");
Unbounded_IO.Put_Line(F, Data);
Close(F);
end UTIO_Demo;
If you'd prefer not to use the Unbounded_IO package, use To_String and To_Unbounded_String to convert back and forth between Unbounded_String values and the strings being read and written via Text_IO.
I would personally just use Unbounded_String, as suggested by Marc C, but if you want to avoid that, you could do something like this:
with Ada.Text_IO;
with Ada.Containers.Indefinite_Doubly_Linked_Lists;
use Ada.Text_IO;
use Ada.Containers;
procedure Uppgift is
type Bil_Register (Namn_Length : Natural) is
record
Namn : String (1 .. Namn_Length);
-- Other components removed for brevity.
end record;
package BR_Container is new Indefinite_Doubly_Linked_Lists (Bil_Register);
use BR_Container;
BR_List : BR_Container.List;
BR_List_Cursor : BR_Container.Cursor;
Buffer : String (1 .. 100);
Length : Natural;
Register_File : File_Type;
Test_File : File_Type;
begin
-- First we read the contents of register.txt and add all the data to
-- our list of Bil_Register objects.
Open (File => Register_File,
Mode => In_File,
Name => "register.txt");
while not End_Of_File (File => Register_File) loop
Get_Line (File => Register_File,
Item => Buffer,
Last => Length);
declare
BR : Bil_Register
(Namn_Length => Length);
begin
BR.Namn := Buffer (1 .. Length);
BR_List.Append (New_Item => BR);
end;
end loop;
Close (File => Register_File);
-- Then we output the contents of our list of Bil_Register objects to
-- test.txt
Create (File => Test_File,
Mode => Out_File,
Name => "test.txt");
BR_List_Cursor := BR_List.First;
while Has_Element (Position => BR_List_Cursor) loop
Put_Line (File => Test_File,
Item => Element (Position => BR_List_Cursor).Namn);
Next (Position => BR_List_Cursor);
end loop;
Close (File => Test_File);
end Uppgift;
I've divided read and write into two blocks because you said:
...do all the read from the input file first before I begin writing to the out file
Obviously with this method, you're going to have to size the Buffer variable appropriately. But really, it's pretty clumsy, compared to just using Unbounded_String. I'd say, that unless you have some very specific concerns or requirements, Unbounded_String is probably the way to go. It will simplify things immensely.
Good luck! :o)
Generally you can get away without having to have a special "length" variable in Ada. Sadly, this one of the cases where that is very difficult to pull off.
There is however a trick that lets you do it in this case. If you don't mind a little recursion, and either don't expect your strings to be tremendously long, or don't care about execution speed too much (you are doing an I/O anyway, so it's going to be slow). If this sounds OK to you, try Carlisle's trick.
function Next_Line(File : in Ada.Text_IO.File_Type :=
Ada.Text_Io.Standard_Input) return String is
Answer : String(1..256);
Last : Natural;
begin
Ada.Text_IO.Get_Line(File => File,
Item => Answer,
Last => Last);
if Last = Answer'Last then
return Answer & Next_Line(File);
else
return Answer(1..Last);
end if;
end Next_Line;
Now you can change your code to:
begin
Open(Infil, In_File, "register.txt");
Create(Utfil, Out_File, "test.txt");
Put_Line(Utfil, Next_Line (Infil));
Close(Infil);
Close(Utfil);
end Uppgift;
精彩评论