首页 文章

阿达 - 阅读大文件

提问于
浏览
1

我正在构建一个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,而另一个长度为mod 1048576,但我不确定如何依次使用这两个读取器 .

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

1 回答

  • 7

    我使用 Stream_IOARM A.12.1),它允许您读入缓冲区并告诉您实际读取了多少数据;见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)中描述的语义,

    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),即没有字节 .

    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;
    

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

相关问题