Максимальный размер/смещение потокового файла с использованием Ada.Streams.Stream_IO.Read

Я пытаюсь прочитать определенные блоки данных (около 4096 байт) из (возможно) огромного файла.

Используя Ada.Streams.Stream_IO.Read() с компилятором GNAT, какое максимальное смещение я мог бы использовать? То есть, если бы я хотел прочитать последние 4 килобайта файла, используя

type Block_Array is array (1..4096) of Positive;
...
Ada.Streams.Stream_IO.Read(File, Block_Array, Last, Offset);

насколько большим может быть смещение (и, следовательно, файл)?

Проведя небольшое исследование, Offset похоже, что в GNAT определяется как 2 ** mod Standard'Address_Size [1], что будет 2^32 на 32-битной машине. Мне не совсем ясно, относится ли это к битам, байтам, килобайтам или еще к какому-то неясному множителю.

Предположим, что это означает байты, не означает ли это, что самый большой файл, который я могу обработать, будет иметь размер 32 гигабайта ((2^32*8)/1024^3)? Если да, то есть ли способ сделать это больше?


Поскольку было предложено, чтобы я не проверял (язык) справочное руководство, вот исследование, которое в первую очередь привело меня к вопросу:

В [2] процедура read определяется как:

procedure Read (File : in  File_Type;
                Item : out Stream_Element_Array;
                Last : out Stream_Element_Offset;
                From : in  Positive_Count);

Чуть выше:

type    Count          is range 0 .. *implementation-defined*;
subtype Positive_Count is Count range 1 .. Count'Last;

Как видно, фактический диапазон Count определяется реализацией. Поскольку я использую компилятор GNAT (см. выше), я проверил [1]. Это говорит о том, что

Стандартные пакеты ввода-вывода, описанные в Приложении A для [...] Ada.Stream_IO [...], реализованы с использованием средства потоков библиотеки C; где [...] Все операции ввода/вывода используют fread/fwrite.

В той же документации ниже

function fread
     (buffer : voids;
      size : size_t;
      count : size_t;
      stream : FILEs)

куда

type size_t is mod 2 ** Standard'Address_Size;

Опять же, Standard'Address_Size будет 32 на 32-битной машине (я также проверил, прежде чем спрашивать, так ли это на моем компьютере). Я также до сих пор не уверен после прочтения как справочного руководства по языку, так и документации по реализации GNAT, относится ли Stream_Element_Offset к байтам или чему-то другому.

Но опять же, если предположить, что это означает байты, не означает ли это, что самый большой файл, который я могу обработать, будет иметь размер 32 гигабайта ((2^32*8)/1024^3)? Если да, то есть ли способ сделать это больше?

[1]: Реализация стандартного ввода-вывода — Справочное руководство по GNAT

[2]: Справочное руководство по Ada - A.12.1 Пакет Streams.Stream_IO


person alex    schedule 22.05.2015    source источник
comment
Не похоже, что вы искали спецификацию пакета Ada.Streams.Stream_IO в справочнике по языку (раздел A.12.1).   -  person Jacob Sparre Andersen    schedule 22.05.2015
comment
@JacobSparreAndersen Ну, похоже, что на самом деле это не так. Пожалуйста, смотрите редактирование в моем вопросе. Кроме того, снисходительность никогда не помогает. Если есть что-то, что я пропустил (что, вероятно, и является частью того, почему я спрашиваю), пожалуйста, не стесняйтесь дать проницательный ответ.   -  person alex    schedule 23.05.2015
comment
32 гигабита, а не гигабайты.   -  person Simon Wright    schedule 24.05.2015
comment
На самом деле, думаю, 16 гигабит - Stream_Element_Offset подписано.   -  person Simon Wright    schedule 24.05.2015
comment
О да. Значит, вы тоже думаете, что Stream_Element_Offset относится к битам, а не к байтам? Я читал, что Stream_Element_Array может использовать байты. Но я очень, очень запутался в этой части. Ваши комментарии действительно кажутся правдоподобными. Спасибо!   -  person alex    schedule 24.05.2015


Ответы (3)


В Mac OS X с FSF GCC 5.1.0 есть

procedure Read
  (File : File_Type;
   Item : out Stream_Element_Array;
   Last : out Stream_Element_Offset;
   From : Positive_Count);

куда

type Count is new Stream_Element_Offset
  range 0 .. Stream_Element_Offset’Last;

subtype Positive_Count is Count range 1 .. Count’Last;            --'
--  Index into file, in stream elements

и (в Ada.Streams)

type Stream_Element_Offset is new Long_Long_Integer;

то есть 64 бита .. должно хватить.

Однако, как отмечает Алекс, GNAT GPL 2014

type Stream_Element_Offset is range
  -(2 ** (Standard'Address_Size - 1)) ..
  +(2 ** (Standard'Address_Size - 1)) - 1;

это означает, что на 32-битной машине вы ограничены файлами размером 2 гигабайта.

Последние исходники FSF GCC (как для 5.1.0 выше) были изменены; нам придется подождать до GNAT GPL 2015, чтобы увидеть, что является окончательным.

Еще одной причиной для беспокойства является код GNAT GPL 2014 для Ada.Streams.Stream_IO.Set_Position (внутренняя подпрограмма).

procedure Set_Position (File : File_Type) is
   use type System.CRTL.long;
   use type System.CRTL.ssize_t;
   R : int;
begin
   if Standard'Address_Size = 64 then
      R := fseek64 (File.Stream,
                    System.CRTL.ssize_t (File.Index) - 1, SEEK_SET);
   else
      R := fseek (File.Stream,
                  System.CRTL.long (File.Index) - 1, SEEK_SET);
   end if;

   if R /= 0 then
      raise Use_Error;
   end if;
end Set_Position;

тогда как версия GCC 5.1.0 (у которой нет альтернативных реализаций)

procedure Set_Position (File : File_Type) is
   use type System.CRTL.int64;
   R : int;
begin
   R := fseek64 (File.Stream, System.CRTL.int64 (File.Index) - 1, SEEK_SET);

   if R /= 0 then
      raise Use_Error;
   end if;
end Set_Position;

Если в вашей системе есть fseek64() - или, возможно, fseeko(), что принимает off_t, а не long для параметра offset - и друзья (я думаю, что так и должно быть, глядя на код выше), я думаю, что было бы не слишком сложно написать свой собственную версию Ada.Streams.Stream_IO, чтобы всегда использовать 64-битные функции. Вероятно, проще всего назвать его My_Stream_IO и стиснуть зубы о предупреждениях компилятора об использовании внутренних модулей GNAT, а не пытаться вставить его в иерархию Ada.

person Simon Wright    schedule 22.05.2015
comment
Это верно, но только для FSF GCC, а не для GNAT, как в моем ответе. Поскольку Mac OS X в течение некоторого времени является только 64-битной, кажется логичным, чтобы она имела 64-битные переменные. Мне кажется, что на 64-битных машинах GNAT также позволит использовать такие огромные файлы, но, в частности, на 32-битных машинах в настоящее время существует ограничение на довольно разумные размеры файлов. - person alex; 23.05.2015
comment
FSF GCC является комаром. Если вы используете какую-либо другую сборку Gnat, может быть полезно сказать об этом - и следуйте подходу, изложенному Саймоном, чтобы увидеть, отличается ли ответ для используемой вами реализации от ответа Саймона. - person user_1818839; 23.05.2015
comment
@BrianDrummond Ах, я этого не знал. Тогда FSF, вероятно, означает Free Software Foundation? Ну тогда я использую gcc (GCC) 4.7.4 20140401 for GNAT GPL gpl-2014 (20140405). И для этой версии я думал, что приведенные выше ссылки (добросовестно используя тот же подход, что и Саймон) завершат мой ответ. Это правильно? - person alex; 23.05.2015

Если вы хотите узнать диапазон скалярного типа, вы можете получить доступ к минимальному и максимальному значениям, используя <type>'First и <type>'Last:

with Ada.Text_IO;

procedure Check_Range is
   use Ada.Text_IO;
   subtype Type_To_Check is Integer;
begin
   Put (Type_To_Check'Image (Type_To_Check'First));
   Put (" .. ");
   Put (Type_To_Check'Image (Type_To_Check'Last));
   New_Line;
end Check_Range;
person Jacob Sparre Andersen    schedule 23.05.2015

Если вы хотите получить доступ к файлам большего размера, чем поддерживает стандартная библиотека, вы можете импортировать функции операционной системы, дающие доступ к самым большим файлам, разрешенным вашей операционной системой.

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

person Jacob Sparre Andersen    schedule 23.05.2015