我正在构建一个HTTP服务器,主要是出于学习/好奇的目的,我遇到了以前从未在Ada中遇到过的问题。如果我尝试使用Direct_IO读取太大的文件,我会收到存储错误:堆栈溢出异常。这几乎从未发生过,但是当我请求一个视频文件时,会抛出异常。
所以我有了一次读取和发送1M个字符块的文件的想法,但是这给我留下了End Errors,因为大多数文件的长度都不是1M个字符。我还不完全确定我是否正确,因为之前读取整个文件总是充足的。这是我写的程序:
procedure Send_File(Channel : GNAT.Sockets.Stream_Access; Filepath : String) is
File_Size : Natural := Natural(Ada.Directories.Size (Filepath));
subtype Meg_String is String(1 .. 1048576);
package Meg_String_IO is new Ada.Direct_IO(Meg_String);
Meg : Meg_String;
File : Meg_String_IO.File_Type;
Count : Natural := 0;
begin
loop
Meg_String_IO.Open(File, Mode => Meg_String_IO.In_File, Name => Filepath);
Meg_String_IO.Read(File, Item => Meg);
Meg_String_IO.Close(File);
String'Write(Channel, Meg);
exit when Count >= File_Size;
Count := Count + 1048576;
end loop;
end Send_File;
我曾想过要声明两个单独的Direct_IO包/字符串大小,其中一个长度为1048576,而另一个长度为1048576,但是我不确定如何使用这两个读者顺序。
感谢任何可以提供帮助的人。
答案 0 :(得分:7)
我使用Stream_IO
(ARM A.12.1),它允许您读入缓冲区并告诉您实际读取了多少数据;见the second form of Read
,
procedure Read (File : in File_Type;
Item : out Stream_Element_Array;
Last : out Stream_Element_Offset);
中描述的语义
Read操作从指定的流传输流元素以填充数组Item。转移元素直到转移了Item'Length元素,或者直到达到流的末尾。如果传输了任何元素,则传输的最后一个流元素的索引将在Last中返回。否则,在Last中返回Item'First - 1。只有当到达流的末尾时,Last才会小于Item'Last。
procedure Send_File (Channel : GNAT.Sockets.Stream_Access;
Filepath : String) is
File : Ada.Streams.Stream_IO.File_Type;
Buffer : Ada.Streams.Stream_Element_Array (1 .. 1024);
Last : Ada.Streams.Stream_Element_Offset;
use type Ada.Streams.Stream_Element_Offset;
begin
Ada.Streams.Stream_IO.Open (File,
Mode => Ada.Streams.Stream_IO.In_File,
Name => Filepath);
loop
从File中读取下一个Buffer-full。 Last接收读取的最后一个字节的索引;如果我们在此读取中到达文件结尾,则Last将小于Buffer'Last。
Ada.Streams.Stream_IO.Read (File, Item => Buffer, Last => Last);
写入实际读取的数据。如果File的大小是Buffer'Length的倍数,则最后一次Read将不读取任何字节并返回Last of 0(Buffer'First - 1),因此这将写入Buffer(1 .. 0),即没有字节。 / p>
Ada.Streams.Write (Channel.all, Buffer (1 .. Last));
读取低于Buffer-full的唯一原因是达到了文件结尾。
exit when Last < Buffer’Last;
end loop;
Ada.Streams.Stream_IO.Close (File);
end Send_File;
(另请注意,最好打开和关闭文件在循环外面!)