Ada - 读取大文件

Ada - reading large files

我正在构建一个 HTTP 服务器,主要是为了 learning/curiosity 目的,我遇到了一个以前在 Ada 中从未遇到过的问题。如果我尝试使用 Direct_IO 读取太大的文件,我会收到存储错误:堆栈溢出异常。这几乎不会发生,但是当我请求视频文件时,会抛出异常。

所以我想到了一次读取和发送 1M 字符块的文件,但这给我留下了结束错误,因为大多数文件的长度不会正好是 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 packages/string 大小,其中一个的长度为 1048576,而另一个的文件长度为 mod 1048576,但我我不确定我将如何依次使用这两个阅读器。

感谢任何能提供帮助的人。

我会使用 Stream_IO (ARM A.12.1), which allows you to read into a buffer and tells you how much data was actually read; see the second form of Read,

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

具有 ARM 13.13.1 (8)

中描述的语义

The Read operation transfers stream elements from the specified stream to fill the array Item. Elements are transferred until Item'Length elements have been transferred, or until the end of the stream is reached. If any elements are transferred, the index of the last stream element transferred is returned in Last. Otherwise, Item'First - 1 is returned in Last. Last is less than Item'Last only if the end of the stream is reached.

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

从文件中读取下一个缓冲区已满。 Last 接收读取的最后一个字节的索引;如果我们在这次读取中到达文件末尾,Last 将小于 Buffer'Last。

      Ada.Streams.Stream_IO.Read (File, Item => Buffer, Last => Last);

写入实际读取的数据。如果 File 的大小是 Buffer'Length 的倍数,则最后一次读取将不读取任何字节并且将 return 一个 Last of 0 (Buffer'First - 1),因此这将写入 Buffer (1 .. 0),即没有字节。

      Ada.Streams.Write (Channel.all, Buffer (1 .. Last));

读取不到缓冲区满的唯一原因是已到达文件末尾。

      exit when Last < Buffer’Last;
   end loop;
   Ada.Streams.Stream_IO.Close (File);
end Send_File;

(另请注意,最好在循环外打开和关闭文件!)