开发者

File IO in ada, how to write Strings to file?

开发者 https://www.devze.com 2023-03-15 23:07 出处:网络
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

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;
0

精彩评论

暂无评论...
验证码 换一张
取 消