【问题标题】:Procedure to open, write and append in Ada在 Ada 中打开、写入和附加的过程
【发布时间】:2011-03-11 11:37:44
【问题描述】:

这个问题是

帖子的后续问题

Ada file operation: instantiation and exception

关于在 Ada 中写入文件。

我选择将此问题放在单独的帖子中,以便更多人看到它,因为我已经在上述帖子中接受了一个稍微不同的问题(即文件处理中的异常)的答案。

WITH Ada.Sequential_IO;
WITH Ada.Float_Text_IO;

PROCEDURE TEST is

package Seq_Float_IO is new Ada.Sequential_IO (Element_Type => Float);
X_File : Seq_Float_IO.File_Type;
File_Name : String;


procedure Open_Data(File : in out Seq_Float_IO.File_Type; 
Name : in String) is

BEGIN

   begin
      Seq_Float_IO.Open (
         File => File,
         Mode => Seq_Float_IO.Append_File,
         Name => File_Name );
   exception
      when Seq_Float_IO.Name_Error =>
      Seq_Float_IO.Create (
         File => File,
         Mode => Seq_Float_IO.Out_File,
         Name => File_Name);
   end;

END Open_Data;


x        : CONSTANT Float := 2.0;


BEGIN --main program
   Open_Data(X_File, "xvalues.dat");
   Seq_Float_IO.Write(File => X_File,Item => x);

   Seq_Float_IO.Close(File => X_File);
END TEST;

在编译上面我得到一个错误如下:

  1. X_File : Seq_Float_IO.File_Type;
    1. 文件名:字符串; |

      不允许无约束的子类型(需要初始化) 提供初始值或显式数组边界

我不知道两件事:

  1. 我有 File_Name : String;因为我希望能够写入不同的文件。所以我想要一个通用字符串,而不是这样的:

File_Name : CONSTANT String := "one_File_Only.dat"

  1. 将过程 Open_Data 保存在单独的 ads 和 adb(用于正文)文件中会更好吗?

非常感谢...


新...

我将代码修改如下:

WITH Ada.Sequential_IO;

PROCEDURE TEST1 is

package Seq_Float_IO is new Ada.Sequential_IO (Element_Type => Float);
X_File, Y_File : Seq_Float_IO.File_Type;
Name_X : CONSTANT String := "domainvalues.dat";
Name_Y : CONSTANT String := "ordinatevalues.dat";


procedure Open_Data(File : in out Seq_Float_IO.File_Type; Name : in String) is

BEGIN

   begin
    Seq_Float_IO.Open (
         File => File,
         Mode => Seq_Float_IO.Append_File,
         Name => Name_X );
    exception
      when Seq_Float_IO.Name_Error =>
         Seq_Float_IO.Create (
            File => File,
            Mode => Seq_Float_IO.Out_File,
            Name => Name_X);
   end;

END Open_Data;


x        : CONSTANT Float := 2.0;


BEGIN --main program
   Open_Data(File => X_File, Name => Name_X);
   Seq_Float_IO.Write(File => X_File, Item => x);
   Seq_Float_IO.Close(File => X_File);

   Open_Data(File => Y_File, Name => Name_Y);
  Seq_Float_IO.Write(File => Y_File, Item => x);
  Seq_Float_IO.Close(File => Y_File);

END TEST1;

如你所见,我有

Seq_Float_IO.Open (
             File => File,
             Mode => Seq_Float_IO.Append_File,
             Name => Name_X );

我已将 Name_X 作为 Name 所采用的参数,但这不正确,因为我应该能够传入一个通用名称,它可以是 Name_X 或 Name_Y。对不起,伙计们,我不知道该放什么。

非常感谢您的帮助。谢谢

【问题讨论】:

  • 你到底为什么在 Open 调用中继续写Name => Name_X?你觉得Open_Data的参数有什么意义?你用File 做正确的事,现在用Name 做正确的事。写Name => Name。删除Name_X、Name_Y。在对Open_Data 的调用中将所需的实际文件名作为文字字符串传递(有关格式,请参见下面的答案)。
  • 非常感谢您对我的耐心等待。
  • 是的,我知道放置 Name_X 会破坏为打开和写入过程创建过程的意义。我只是不知道该放什么。 Ada 中的文件 IO 似乎很难,我需要更仔细地研究这部分。书中的例子并不全面……他们倾向于坚持简单的文件操作。
  • 我认为删除 Name_X 和 Name_Y 并按照您的建议传递实际文件名以简化代码是一件好事。但我会保留这两个版本,以便从错误中吸取教训。
  • re: 耐心——很抱歉,已经很晚了,我无法弄清楚问题的哪一部分是症结所在。不管怎样,这一关已经过去了,祝你下一关好运!

标签: file-io ada procedure


【解决方案1】:

@Simon Wright 的答案是正确的,您可能会发现将他的答案与我之前写的 second one 进行比较会有所帮助。请注意,如果您有

Name_X : constant String := "domainvalues.dat";
Name_Y : constant String := "ordinatevalues.dat";

Name_X 或Name_Y 中的任一个字符串都可以用作Open_Data 的实际Name 参数。形式参数Name 的类型为String。 String 不受约束,它可以是任何(实现定义的)最大长度。相比之下,Name_X 和 Name_Y 都有一个由其初始分配确定的固定长度。

附录:您编写了一个带有 String 类型的形式参数 (Name) 的子程序,具有此签名

procedure Open_Data(
    File : in out Seq_Float_IO.File_Type;
    Name : in String) is ...

在实现中,您希望将收到的String 作为实际参数(Name)转发到Open,而不是全局常量的名称(Name_X)。

Seq_Float_IO.Open (
    File => File,
    Mode => Seq_Float_IO.Append_File,
    Name => Name );

【讨论】:

  • 是的,我知道放置 Name_X 会破坏为打开和写入过程创建过程的意义。我只是不知道该放什么。 Ada 中的文件 IO 似乎很难,我需要更仔细地研究这部分。书中的例子并不全面......他们倾向于坚持简单的文件操作。
  • 完成投票。我开始真正喜欢艾达了。我主要使用C和Matlab。 Ada 有助于避免科学计算中其他语言中容易出现的错误。然而,很少有教科书展示 Ada 在数值计算中的应用。 Ada 2005 为矩阵运算(例如特征值的计算)引入了新功能,这在我的待办事项探索清单上。再次感谢。
  • 我特别喜欢 Ada 冗长的风格。 Ada 来自 C,感觉很罗嗦,但这对程序的可维护性有很大帮助。现在我养成了写长而有意义的变量名的好习惯,这是我在用 C 语言编写时没有做的事情。
【解决方案2】:

关于 Ada 中普通的 String 的事情是,一个特定的字符串,比如你的 File_Name,必须是固定长度的;但是不同的字符串可以有不同的长度。

你可以写

S1 : String := "1234";
S2 : String := "12345";

在这种情况下,S1 的长度为 4,分配给它的长度必须为 4。你可以写

S1 := "abcd";

但如果你尝试写

S1 := "pqrst";

或

S1 := S2;

你会得到一个Constraint_Error。

对于子程序的字符串参数,例如您的Open_Data,字符串参数Name 具有长度——当然还有值!调用中的实际参数。所以你可以说

Open_Data (X_File, "x.dat");
Open_Data (Y_File, "a_very_long_name.dat");

你之前遇到过问题

procedure Open_Data(File : in out Seq_Float_IO.File_Type; 
                    Name : in String) is
begin
   Seq_Float_IO.Open (File => File,
                      Mode => Seq_Float_IO.Append_File,
                      Name => ????);

我不愿意只告诉你答案,所以 - 考虑File => File 部分。第一个File 是Seq_Float_IO.Open 的形参名称,第二个File 是要传递的,在本例中是Open_Data 的File 参数。

如果我指出我可以将上面的调用写成这样可能会有所帮助

Open_Data (File => X_File, Name => "x.dat");
Open_Data (File => Y_File, Name => "a_very_long_name.dat");

【讨论】:

  • 感谢字符串解释。我在一本书中看到了一个示例,其中包含: File_Name : CONSTANT String := "one_File_Only.dat" 正如我在帖子中提到的那样……但当然,将其扩展到任何字符串都会有所帮助。再次感谢。
猜你喜欢
  • 2014-12-02
  • 2022-06-25
  • 2017-04-09
  • 2011-05-27
  • 2021-12-31
  • 2014-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多