使用Ada.Streams.Stream_IO.Read

时间:2015-05-22 16:22:27

标签: io filestream ada gnat

我尝试从(可能的)大文件中读取特定的数据块(大约4096字节)。

在GNAT编译器中使用Ada.Streams.Stream_IO.Read(),我可以使用的最大偏移量是多少?也就是说,如果我想读取文件的最后4千字节,请使用

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

Offset有多大(因此文件)?

进行一些研究,Offset似乎在GNAT中定义为2 ** mod Standard'Address_Size [1],在32位机器上为2^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中描述的标准I / O包   [...] 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]:The Implementation of Standard I/O - GNAT Reference Manual

[2]:Ada Reference Manual - A.12.1 The Package Streams.Stream_IO

3 个答案:

答案 0 :(得分: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位..应该就够了。

然而,正如Alex指出的那样,GNAT GPL 2014已经

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

这意味着,在32位计算机上,您只能使用2 GB的文件。

最新的FSF GCC来源(上述5.1.0)已经改变;我们将不得不等到GNAT GPL 2015看看哪个是最终的。

作为进一步引起关注的问题,Ada.Streams.Stream_IO.Set_Position(内部子程序)的GNAT GPL 2014代码是

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层次结构时要抓紧了。

答案 1 :(得分:0)

如果您想知道标量类型的范围,可以使用<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;

答案 2 :(得分:0)

如果要访问大于标准库支持的文件,可以导入操作系统函数,以访问操作系统允许的最大文件。

从其他语言导入功能的详细信息在语言参考手册的附录B中说明。