我正在构建一个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;
Run Code Online (Sandbox Code Playgroud)
我曾想过要声明两个单独的Direct_IO包/字符串大小,其中一个长度为1048576,而另一个长度为mod 1048576,但我不确定如何依次使用这两个读取器.
感谢任何能提供帮助的人.
我使用Stream_IO(ARM A.12.1),它允许您读入缓冲区并告诉您实际读取了多少数据; 看到第二种形式Read,
procedure Read (File : in File_Type;
Item : out Stream_Element_Array;
Last : out Stream_Element_Offset);
Run Code Online (Sandbox Code Playgroud)
使用ARM 13.13.1(8)中描述的语义,
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
Run Code Online (Sandbox Code Playgroud)
从File中读取下一个Buffer-full.Last接收读取的最后一个字节的索引; 如果我们在此读取中到达文件结尾,则Last将小于Buffer'Last.
Ada.Streams.Stream_IO.Read (File, Item => Buffer, Last => Last);
Run Code Online (Sandbox Code Playgroud)
写下实际读取的数据.如果File的大小是Buffer'Length的倍数,则最后一次Read将不读取任何字节并返回Last of 0(Buffer'First - 1),因此这将写入Buffer(1 .. 0),即没有字节.
Ada.Streams.Write (Channel.all, Buffer (1 .. Last));
Run Code Online (Sandbox Code Playgroud)
读取少于Buffer-full的唯一原因是达到了文件结尾.
exit when Last < Buffer’Last;
end loop;
Ada.Streams.Stream_IO.Close (File);
end Send_File;
Run Code Online (Sandbox Code Playgroud)
(另请注意,最好在循环外打开和关闭文件!)