我尝试从(可能的)大文件中读取特定的数据块(大约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
答案 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中说明。