【问题标题】:Ada - reading large filesAda - 读取大文件
【发布时间】:2015-10-13 01:37:13
【问题描述】:

我正在构建一个 HTTP 服务器,主要是出于学习/好奇的目的,但我遇到了一个以前在 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 包/字符串大小,其中一个长度为 1048576,而另一个长度为文件长度 mod 1048576,但我不确定如何按顺序使用这两个阅读器.

感谢任何可以提供帮助的人。

【问题讨论】:

    标签: file ada


    【解决方案1】:

    我会使用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);
    

    具有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;
    

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

    【讨论】:

    • 太棒了,我玩了一下这个,发现这适用于大于缓冲区范围的文件,所以这个问题应该会得到解决。不过,现在我有一个不同的问题。我正在测试的图像文件和视频无法正确发送。当我尝试使用 Ada.Text_IO 读取这些文件时,它看起来与我之前遇到的问题相同。在那种情况下,我认为这是因为文件的编码方式不适合 Text_IO 包。有什么想法吗?
    • 哎呀,没关系。那是我做错的另一件事,完全无关。谢谢一百万。
    • 展示答案的好方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-15
    • 2011-05-21
    • 1970-01-01
    • 1970-01-01
    • 2014-01-13
    相关资源
    最近更新 更多