Файл IO в Аде, как записать строки в файл? - PullRequest
3 голосов
/ 26 июня 2011

У меня возникла проблема с записью строковой переменной в файл. Проблема в том, что я должен указать точную длину этой строки. В противном случае выходной файл будет просто содержать некоторые значения записок. Интересно, можно ли это как-то решить без необходимости указывать длину строки перед раздачей?

Я знаю, что моя Get() процедура хранит длину этой переменной, и я просто мог вернуть ее в основную программу. Однако я хочу написать свою программу, чтобы она сначала выполняла все операции чтения из входного файла, прежде чем начать запись в выходной файл.

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;

-

РЕДАКТИРОВАТЬ (2011.08.20)

Кажется, это проблема только для ОС на базе Unix. При использовании Windows вам не обязательно быть абсолютным с размером строки, когда вы печатаете ее в файл или на экран

Ответы [ 3 ]

6 голосов
/ 26 июня 2011

Ну, длина действительной части строки должна отслеживаться где-то .

Вы можете сохранить действительную длину каждого из строковых полей вашей записи как отдельное поле:

Namn        : String (1..50);
Namn_Length : Natural;

Вы можете определить свой собственный тип переменной типа пакета или использовать уже существующий пакет, такой как Variable_Length .Например,

Namn : Variable_Length.Variable_String(50);

Вы можете использовать Unbounded_String для полей и переменных:

Namn : Unbounded_String;

И Ada.Text_IO.Unbounded_IO для ввода / вывода:

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;

Если вы не хотите использовать пакет Unbounded_IO, используйте To_String и To_Unbounded_String для преобразования туда и обратно между значениями Unbounded_String и строками, читаемыми и записываемыми с помощью Text_IO.

2 голосов
/ 27 июня 2011

Лично я бы просто использовал Unbounded_String, как предложено Марком Си, но если вы хотите избежать этого, вы можете сделать что-то вроде этого:

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;

Я разделил чтение и запись на два блока, потому что вы сказали:

... сделать все чтение из входного файла прежде чем я начну писать выходной файл

Очевидно, что с этим методом вам нужно будет соответствующим образом изменить размер переменной Buffer. Но на самом деле, это довольно неуклюже по сравнению с использованием Unbounded_String. Я бы сказал, что если у вас нет особых проблем или требований, Unbounded_String, вероятно, является подходящим вариантом. Это очень упростит вещи.

Удачи! : О)

0 голосов
/ 27 июня 2011

Как правило, вы можете уйти, не имея специальной переменной длины в Ada. К сожалению, это один из случаев, когда это очень трудно осуществить.

Однако в этом случае есть хитрость, которая позволяет вам сделать это. Если вы не возражаете против небольшой рекурсии и либо не ожидаете, что ваши строки будут чрезвычайно длинными, либо не слишком заботитесь о скорости выполнения (вы все равно делаете ввод-вывод, поэтому он будет медленным) , Если это звучит нормально, попробуйте трюк Карлайла .

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;

Теперь вы можете изменить свой код на:

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