首页 文章

如何在从Ada中的Stream读取数据时调整记录组件的大小/匹配?

提问于
浏览
3

非常具体的问题,但我们在这里有一些好的阿达人,所以我想听听他们的想法 . 我正在从用于嵌入式系统的文件中读取数据 . 我正在使用的数据块总是具有可预测的头格式......但是有一个问题......数据有效载荷长度是在有效载荷发生之前作为格式的一部分给出的 . 因此,在读取标头中已知位置的某个字节之前,我不知道有效负载大小 . 这些块一个接一个地出现 .

字面上格式是([]用于可读性):

[ 2byte TAG ] [ 1byte length of payload (LSB) ] [ 1byte length of payload (MSB) ] [ PAYLOAD ]

有效负载是人类可读的配置文本 . 下一个TAG将是前一个有效载荷之后的下两个字节,依此类推,直到我在最后一个有效载荷之后看不到任何匹配的已知TAG . 然后我知道我已经完成了 .

我正在使用direct_IO流从文件中读取此内容,但我可能会切换到更常规的流并开始执行转换 .

我想在一天结束时将所有这些存储在一个简单的记录中我正在寻找一种技术,我可以读取数据并读取第3个字节,我现在知道有效载荷大小并可以调整数组的大小或字符串组件,用于在记录已充当读缓冲区的同时保持数据正确 . 那就是我需要读取TAG和长度数据,所以我想将它们立即存储在记录中 . 如果可以,我想将有效负载存储在同一记录中 . 我可以考虑使用访问类型并动态创建有效负载存储,但这意味着我必须在3个字节后停止读取,执行工作,然后继续 . 另外,这意味着写入将具有相同的问题,因为对象的表示不再与期望的块格式匹配 .

我正在考虑尝试使用记录来保存所有这些,并对有效负载大小进行判别,并在该记录上使用表示子句来模仿上述格式 . 由于判别式是记录和数据块中的第三个字节,我可以进行对话并简单地将数据“放置”到对象中......但是当我实例化时,我没有办法调整组件的大小 . 没有读过TAG和长度的记录 . 我假设我无法同时读取AND创建对象,因此要创建对象我需要一个长度 . 虽然我可以继续摆弄文件位置并阅读我需要的内容,然后回到开头,然后创建并使用整个块,我知道必须有一个更好的“Ada”方式 .

有没有办法可以使用表示子句将 Headers 填充到记录中,当判别符填充数据中的值时,将设置记录数组或字符串有效负载组件大小?

此外,这不只是用于阅读,我需要找到一种在配置更改时将这种确切格式输出到文件中的好方法 . 所以我希望使用表示子句来匹配底层格式,这样我就可以将对象“写”到文件中,这将是正确的格式 . 我希望对读取做同样的事情 .

到目前为止,我所看到的所有Ada读取的示例都是知道长度(或已知最大长度)的记录,其中记录读取静态大小的数据块 .

有人有一个例子或者能指出我如何使用这种方法来处理这种可变大小的有效载荷吗?

感谢您的任何帮助,您可以提供,

-Josh

3 回答

  • 3

    基本上,这样做的方法是进行部分读取,足以获得字节数,然后将其余数据读入区分记录 .

    像伪Ada中的以下内容:

    type Payloads is array (Payload_Sizes range <>) of Your_One_Byte_Payload_Type;
    
    type Data (Payload_Length : Payload_Sizes) is
       record
          Tag : Tag_Type;
          Payload : Payloads(1 .. Payload_Length);
       end record;
    
    for Data use record
       Tag            at 0 range 0 .. 15;
       Payload_Length at 2 range 0 .. 15;
       -- Omit a rep spec for Payload
    end record;
    

    通常,编译器会在最后一个rep-spec字段之后立即找到Payload数据,但您需要与供应商进行验证,或者执行一些测试程序 . (可能有更明确的方式来指定这一点,如果有人提供可行的方法,我愿意更新此答案 . )

    并且不提供Payload_Length判别式的默认值,这将导致记录的实例始终保留最大值所需的最大存储量 .

    然后,在您的数据读取代码中,有以下几点:

    loop
       Get(Data_File, Tag);
       Get(Data_File, Payload_Length)
    
       declare
          Data_Item : Data(Payload_Length);
       begin
          Data_Item.Tag := Tag;
          Get(Data_File, Data_Item.Payload);
          Process_Data(Data_Item);
       end;
       ...
       exit when Whatever;
    end loop;
    

    (您需要制定退出标准 . )

    然后将为Payload_Length动态调整Data_Item的大小 . 但要注意,如果长度是奇数,则可能会出现填充...

  • 4

    这种情况正是 'input 属于语言的属性 .

    如果您还拥有首先将该数据写入流的代码,那么这很容易 . 只是用

    Myobject : Discriminated_Record := Discriminated_Record'input (Some_Stream'access);
    

    (当然,写作时使用 'output ) .

    如果你必须读取其他人的格式化数据,它会变得更复杂一些 . 您必须实现自己的 'input 例程 .

    function Discriminated_Record_Input 
        (Stream : access Ada.Streams.Root_Stream_Type'class) 
    return Discriminated_Record;
    for Discriminated_Record'input use Discriminated_Record_Input;
    

    Discriminated_Record_Input 的实现中,您可以通过执行所有操作来解决判别问题声明部分,或使用本地声明块 . (警告:未编译的代码)

    function Discriminated_Record_Input
        (Stream : access Ada.Streams.Root_Stream_Type'class) 
    return Discriminated_Record is
    
        Size : constant Natural := Natural'input(Stream);
        Data : constant Discriminated_Record_Input 
            := (Size, (others => Byte_Type'input(Stream));
    begin
        return Data;
    end Discriminated_Record_Input;
    

    这样做的主要缺点是您的数据可能会被复制两次(一次进入局部常量,然后再次进入 MyObject ) . 一个好的优化器可能会解决这个问题,就像在语言中添加左值引用一样(但我不打算考虑) .

  • 0

    在Marc Cs和TEDs答案的基础上,需要考虑以下几点:

    • 如前所述,这是一个嵌入式系统,我还会阅读有关动态内存分配的项目要求,因为许多嵌入式系统明确禁止动态内存分配/解除分配 . (检查你的ada.streams的实现)

    • 您描述的格式让人想起Satellite Payload格式,我是否正确?如果是这样,请仔细阅读规范,因为那些'尺寸' are often more correctly termed '从此点开始的最大可转位偏移量从0'开始,即大小-1 .

    • 一个Discriminent记录可能是要走的路,但你可能必须使用长度字段(不是判别式)使它成为一个不可变的记录,以保证你的程序不会分配太多的内存 . 将其修复为“合理的最大值” .

相关问题