跳转到内容

Ada 编程/库/Ada.Directories

来自 Wikibooks,开放的书籍,开放的世界

Ada. Time-tested, safe and secure.
Ada. 经久耐用,安全可靠。

此语言特性仅从 Ada 2005 开始可用。

Ada.Directories 是自 Ada 2005 以来 预定义语言环境 的一个单元。它允许对文件系统目录进行各种操作和查询。

如果环境支持文件和目录的概念,那么可以使用 Ada.Directories 以一种相当独立于操作系统的 방식 来操作它们。

这是一个高度依赖于实现的包,因此,可以从文件中提取的信息和关于目录的信息被保持在非常基本的水平。如果需要更多信息(所有者、组等),则应为此创建子包,如 Ada 参考手册 [1] 中的实现建议所述。

如果其他信息关于文件(如所有者或创建日期)在目录条目中可用,则实现应该在一个名为 Directories.Information 的子包中提供函数来检索它。

简短使用教程

[编辑 | 编辑源代码]

本节概述了 Ada.Directories 包的使用。如果还不够详细,你也可以参考 详细使用教程

遍历目录

[编辑 | 编辑源代码]

使用 Set_Directory 来更改当前工作目录。其余函数相当直白,除了 Containing_Directory,它返回包含给定目录的目录的名称。

   function Current_Directory return String;
   procedure Set_Directory (Directory : in String);
   function Exists (Name : in String) return Boolean;
   function Containing_Directory (Name : in String) return String;

枚举目录条目

[编辑 | 编辑源代码]

这个例子列出了当前工作目录中所有以 ".gpr" 结尾的条目。Start_Search 过程用于开始枚举目录。如果要删除筛选条件,可以传递一个空字符串。遍历目录涉及调用 Get_Next_Entry 来返回下一个目录条目,并调用 More_Entries 来检查是否有更多条目。搜索完成后,调用 End_Search

   type Search_Type is limited private;
   type Directory_Entry_Type is limited private;

   procedure Start_Search (Search    : in out Search_Type;
                          Directory : in String;
                          Pattern   : in String;
                          Filter    : in Filter_Type := (others => True));
   procedure Get_Next_Entry (Search : in out Search_Type; Directory_Entry : out Directory_Entry_Type);
   function More_Entries (Search : in Search_Type) return Boolean;
   procedure End_Search (Search : in out Search_Type);

生成的 Directory_Entry_Type 包含完整的名称、简单名称、大小、类型和修改类型。

  function Simple_Name (Directory_Entry : in Directory_Entry_Type) return String;
  function Full_Name (Directory_Entry : in Directory_Entry_Type) return String;
  function Kind (Directory_Entry : in Directory_Entry_Type) return File_Kind; --  Directory, Ordinary_File, Special_File
  function Size (Directory_Entry : in Directory_Entry_Type) return File_Size;
  function Modification_Time (Directory_Entry : in Directory_Entry_Type) return Ada.Calendar.Time;
with Ada.Text_IO;
with Ada.Directories;
use Ada.Text_IO;
use Ada.Directories;
    
procedure Main is
  Dir : Directory_Entry_Type;
  Dir_Search : Search_Type;
  
  Curr_Dir : string := Current_Directory;
begin
  Put("Current Directory: ");
  Put_Line(Curr_Dir);
   
  Start_Search(Search => Dir_Search,
               Directory => Curr_Dir,
               Pattern => "*.gpr");
  loop
     Get_Next_Entry(Dir_Search, Dir);
     
     Put(Full_Name(Dir));
     Set_Col(50);
     
     if Kind(Dir) = Ordinary_File then
        Put(Size(Dir)'Image);
     end if;
     Set_Col(60);
     
    Put_Line(Kind(Dir)'Image);
    
     exit when not More_Entries(Dir_Search);
  end loop;
  
  End_Search(Dir_Search);
  
end Main;

目录操作

[编辑 | 编辑源代码]

使用 Create_Directory 创建目录。Create_Path 创建路径中的所有目录。GNAT Ada 上的目录路径可以包含 "\" 或 "/" 字符。Rename 在目录中重命名目录或文件。<Delete_Tree> 删除整个目录和文件层次结构。Delete_Directory 删除空目录(非空目录抛出 Use_Error 异常)。Delete_File 删除目录中的普通文件。请注意,Form 参数是特定于实现的。在我使用的 GNAT Ada 版本中,它只能用于设置编码。

   procedure Create_Directory (New_Directory : in String; Form : in String := "");
   procedure Create_Path (New_Directory : in String; Form : in String := "");
   procedure Rename (Old_Name, New_Name : in String);
   procedure Delete_Tree (Directory : in String);
   procedure Delete_Directory (Directory : in String);
   procedure Delete_File (Name : in String);

以下是一个简单的例子,它创建一组目录并遍历这些目录。请注意,它在 Windows 和 Linux 上均可运行,使用 "/" 作为路径分隔符。返回的路径分隔符适合文件系统(例如,Windows 返回 "\")。

procedure Main is
  Dir : Directory_Entry_Type;
  Dir_Search : Search_Type;   
begin   
  Start_Search(Search => Dir_Search, Directory => Curr_Dir, Pattern => "");
  
  Create_Path("Foo");
  Create_Path("Bar/Baz/Qux");
  
  loop
     Get_Next_Entry(Dir_Search, Dir);
     Put_Line(Full_Name(Dir));
     exit when not More_Entries(Dir_Search);
  end loop;
  
  End_Search(Dir_Search);
  
  Delete_Directory("Foo");
  Delete_Tree("Bar");
  
end Main;

如果目录条目无效或枚举目录时超过最后一个目录,则会引发 Status_Error。如果目录或文件名无法识别文件或目录(不存在或无效,具体取决于上下文),通常会引发 Name_Error。如果目录不受支持或不可遍历,则会引发 Use_Error

  Status_Error : exception renames Ada.IO_Exceptions.Status_Error;
  Name_Error   : exception renames Ada.IO_Exceptions.Name_Error;
  Use_Error    : exception renames Ada.IO_Exceptions.Use_Error;
  Device_Error : exception renames Ada.IO_Exceptions.Device_Error;

详细使用教程

[编辑 | 编辑源代码]

本文将基于一个名为 aDir 的小程序,随着我们逐步介绍各种函数、过程和类型,我们将向其中添加功能。在最基本的形式中,它所做的只是输出当前默认目录

with Ada.Text_IO;
with Ada.Directories;

procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
end aDir;

运行上面的程序时,你应该看到类似于以下的输出

 Starting default directory: /home/thomas/wiki_examples/aDir

你应该看到的是在你系统上启动 aDir 的目录的路径,而不是上面的路径(/home/thomas/wiki_examples/aDir)。

目录和文件操作

[编辑 | 编辑源代码]

在处理文件和目录时,需要一些基本的功能。我们必须能够移动到特定的目录;我们必须能够复制、重命名和删除文件和目录;我们必须能够创建新目录。幸运的是,这就是接下来的函数和过程使我们能够做的事情。

Current_Directory

[编辑 | 编辑源代码]

Current_Directory 的规范如下所示

function Current_Directory return String;

我们已经看到Current_Directory 如何工作,但关于 Current_Directory 还有一些值得一提的事情

  • Current_Directory 返回当前默认目录的完整目录名称。这并不等于程序本身所在的目录。
  • 返回的目录名称适用于 Set_Directory 过程。
  • 如果操作系统/环境不支持默认目录,则会传播异常 Use_Error

当我们执行上面的基本aDir程序时,输出的是aDir程序在我的系统中所处的路径。但让我们看看如果我们从其他地方调用程序会发生什么。

 $ pwd
 /home/thomas/wiki_examples/aDir
 $ ./adir
 Starting default directory: /home/thomas/wiki_examples/aDir
 $ cd && pwd
 /home/thomas
 $ wiki_examples/aDir/adir
 Starting default directory: /home/thomas

如您所见,Current_Directory 不等于实际程序的路径。相反,它返回当前默认目录,这完全依赖于实现。在上面的例子中,它根据从哪里调用程序而有所不同。因此,除非您使用 Set_Directory 特定地设置了默认目录,否则您无法 100% 确定 Current_Directory 将返回什么路径。

第二个要点是不言自明的,第三个要点我无法测试,因为我目前没有不支持目录概念的系统。

Ada.Directories.Current_Directory 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
end aDir;

Set_Directory

[编辑 | 编辑源代码]

Set_Directory 的规范如下所示

procedure Set_Directory (Directory : String);

使用 Set_Directory,我们可以更改当前默认目录。将这段代码添加到 aDir 程序的主体中,以查看它的工作原理

D.Set_Directory (Directory => "/home/thomas");
IO.Put ("New default directory: ");
IO.Put_Line (Item => D.Current_Directory);

如果我们现在执行程序,我们会得到以下结果

 Starting default directory: /home/thomas/wiki_examples/aDir
 New default directory: /home/thomas

如果要设置的目录不存在,则会引发 Name_Error 异常。让我们看看它是如何工作的

D.Set_Directory (Directory => "/home/does/not/exist");
   
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Directory does not exist.");

如果您将上述代码片段添加到核心 aDir 程序中,您将获得类似于以下的输出

 Starting default directory: /home/thomas/wiki_examples/aDir
 Directory does not exist.

由于 Set_Directory 设置的目录不存在,因此会引发并捕获 Name_Error 异常。但是,您不应该习惯性地使用 Set_Directory 来检查给定目录是否存在。对于这个简单的任务,我们有 Exists 函数。

Ada.Directories.Set_Directory 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   D.Set_Directory (Directory => "/home/thomas");
   IO.Put ("New default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
end aDir;
with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   D.Set_Directory (Directory => "/home/does/not/exist");
 
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Directory does not exist.");
end aDir;

Create_Directory

[编辑 | 编辑源代码]

Create_Directory 的规范如下所示

procedure Create_Directory
  (New_Directory : String;
   Form          : String := "");

使用此过程,我们可以(不出所料)创建新目录。但在尝试之前,我们将首先处理 Form 参数。RM 对此有以下说法

Form 参数可用于提供目录的系统相关特性;Form 参数的解释是实现定义的。Form 的空字符串指定使用新目录实现的默认选项。

对于我的特定环境(Slackware 12.1 和 GNATMAKE GPL 2008 编译器),Form 参数实际上没有任何作用。对于其他实现,情况可能并非如此,但我相当肯定,对于大多数标准系统(Unix、Linux、BSD、Windows),Form 未被使用。因此,Form 应该是一个空字符串,除非您在实现定义了 Form 用法的平台上。

但我们还是先谈谈这个——让我们在 aDir 中添加一些代码,看看 Create_Directory 是如何工作的

D.Create_Directory (New_Directory => "some_dir");

在程序中添加了这一行代码后,我们可以通过进行一些测试来查看程序是如何工作的

 $ ls -l
 -rw-rw-rw- 1 thomas users    502 2009-09-24 22:09 Proj.gpr
 -rwxr-xr-x 1 thomas users 578199 2009-09-29 22:03 adir*
 -rw-rw-rw- 1 thomas users    517 2009-09-29 22:03 adir.adb
 drwxr-xr-x 2 thomas users      0 2009-09-29 22:03 objects/
 $ ./adir
 Starting default directory: /home/thomas/wiki_examples/aDir
 $ ls  -l
 -rw-rw-rw- 1 thomas users    502 2009-09-24 22:09 Proj.gpr
 -rwxr-xr-x 1 thomas users 578199 2009-09-29 22:03 adir*
 -rw-rw-rw- 1 thomas users    517 2009-09-29 22:03 adir.adb
 drwxr-xr-x 2 thomas users      0 2009-09-29 22:03 objects/
 drwxr-xr-x 2 thomas users      0 2009-09-29 22:23 some_dir/
 $ cd some_dir/
 $ ../adir
 Starting default directory: /home/thomas/wiki_examples/aDir/some_dir
 $ ls -l
 drwxr-xr-x 2 thomas users 0 2009-09-29 22:25 some_dir/

从上面可以看出,Create_Directory 在当前默认目录中创建新目录,在本例中,该目录是我们调用 adir 的目录。如果我们想在当前默认目录以外的目录中创建 some_dir 目录,我们必须在 Create_Directory 行之前添加另一行代码

D.Set_Directory (Directory => "/home/thomas/wiki_examples/aDir");

当然,您应该将上面的路径替换为您系统中的路径。

接下来,我们删除已经创建的 some_dir 目录,然后尝试与之前相同的命令链

 $ ls -l
 -rw-rw-rw- 1 thomas users    502 2009-09-24 22:09 Proj.gpr
 -rwxr-xr-x 1 thomas users 578224 2009-09-29 22:32 adir*
 -rw-rw-rw- 1 thomas users    635 2009-09-29 22:32 adir.adb
 drwxr-xr-x 2 thomas users      0 2009-09-29 22:32 objects/
 $ ./adir
 Starting default directory: /home/thomas/wiki_examples/aDir
 $ ls  -l
 -rw-rw-rw- 1 thomas users    502 2009-09-24 22:09 Proj.gpr
 -rwxr-xr-x 1 thomas users 578224 2009-09-29 22:32 adir*
 -rw-rw-rw- 1 thomas users    635 2009-09-29 22:32 adir.adb
 drwxr-xr-x 2 thomas users      0 2009-09-29 22:32 objects/
 drwxr-xr-x 2 thomas users      0 2009-09-29 22:40 some_dir/
 $ cd some_dir/
 $ ../adir
 Starting default directory: /home/thomas/wiki_examples/aDir/some_dir
 raised ADA.IO_EXCEPTIONS.USE_ERROR : creation of new directory "some_dir" failed

我们的程序在第二次创建 some_dir 目录时失败,因为它已经存在,证明程序不再在我们调用程序的任何地方创建 some_dir。这正是我们想要的,虽然我们可能应该添加一些代码来捕获异常,而不是让程序崩溃

exception
   when D.Use_Error =>
      IO.Put_Line ("Directory cannot be created.");

现在让我们再次尝试最后一个命令

 $ ../adir
 Starting default directory: /home/thomas/wiki_examples/aDir/some_dir
 Directory cannot be created.

好多了!

除了 Use_Error 之外,还有 Name_Error,如果给定的名称不是有效的目录,则会引发该错误。让我们尝试将 some_dir 更改为显然不能作为目录名称的东西:一个空字符串。我们只需要更改程序中的一行代码

D.Create_Directory (New_Directory => "some_dir");

D.Create_Directory (New_Directory => "");

现在,运行程序,我们会得到

 Starting default directory: /home/thomas/wiki_examples/aDir/some_dir
 raised ADA.IO_EXCEPTIONS.NAME_ERROR : invalid new directory path name ""

我们可以通过添加另一个异常处理程序来捕获 Name_Error

exception
   when D.Use_Error =>
      IO.Put_Line (Item => "Directory cannot be created.");
   when D.Name_Error =>
      IO.Put_Line (Item => "Directory is not valid.");

运行程序,我们现在得到

 Starting default directory: /home/thomas/wiki_examples/aDir
 Directory is not valid.

完美。


Ada.Directories.Create_Directory 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   D.Set_Directory (Directory => "/home/thomas/wiki_examples/aDir");
   D.Create_Directory (New_Directory => "some_dir");
   --  Running the program multiple times will raise the Use_Error.
   --  Changing some_dir to a null string will raise the Name_Error.
exception
   when D.Use_Error =>
      IO.Put_Line (Item => "Directory cannot be created.");
   when D.Name_Error =>
      IO.Put_Line (Item => "Directory is not valid.");
end aDir;

Delete_Directory

[编辑 | 编辑源代码]

Delete_Directory 的规范如下所示

procedure Delete_Directory (Directory : String);

使用 Delete_Directory,您可以删除一个空的目录,并且程序对其具有足够的权限。Directory 参数接受单个命名目录或目录的完整路径。对于单个名称,会将当前默认目录添加到前面,以创建一个完整路径。

将这些行添加到基本 aDir 程序中,以查看它的实际操作

D.Set_Directory (Directory => "/home/thomas/wiki_examples/aDir");
IO.Put ("New default directory: ");
IO.Put_Line (Item => D.Current_Directory);
   
D.Create_Directory (New_Directory => "some_dir");
if D.Exists (Name => "some_dir") then
   IO.Put_Line ("some_dir exists.");
end if;
D.Delete_Directory (Directory => "some_dir");
   
D.Create_Directory (New_Directory => "some_dir2");
if D.Exists (Name => "some_dir2") then
   IO.Put_Line ("some_dir2 exists.");
end if;
D.Delete_Directory (Directory => "/home/thomas/wiki_examples/aDir/some_dir2");

执行此程序,我们将获得以下输出

 $ ./adir
 Starting default directory: /home/thomas/wiki_examples/aDir
 New default directory: /home/thomas/wiki_examples/aDir
 some_dir exists.
 some_dir2 exists.
 $ ls -l
 -rw-rw-rw- 1 thomas users    502 2009-09-24 22:09 Proj.gpr
 -rwxr-xr-x 1 thomas users 578224 2009-09-30 16:13 adir*
 -rw-rw-rw- 1 thomas users    973 2009-09-30 16:14 adir.adb
 drwxr-xr-x 2 thomas users      0 2009-09-30 16:13 objects/

该示例表明 Delete_Directory 确实可以使用目录的完整路径和仅使用目录名称。这两个 Exists 调用只是为了帮助直观地了解目录实际上是创建的。

如果 Directory 字符串不匹配现有目录,则会引发 Name_Error 异常;如果无法删除目录或目录不是空的,则会引发 Use_Error 异常。将此代码添加到核心 aDir 程序中

Delete_Non_Existing :
declare
begin
   D.Delete_Directory (Directory => "does_not_exist");  
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Directory not found.");
end Delete_Non_Existing;
     
Delete_With_Contents :
declare  
begin
   D.Delete_Directory (Directory => "dir_with_contents");    
exception
   when D.Use_Error =>
      IO.Put_Line (Item => "Cannot delete non-empty directory.");
end Delete_With_Contents;

输出为

 Starting default directory: /home/thomas/wiki_examples/aDir
 Directory not found.
 Cannot delete non-empty directory.

如预期的那样。要删除非空目录,您必须使用 Delete_Tree 过程。


Ada.Directories.Delete_Directory 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   D.Set_Directory (Directory => "/home/thomas/wiki_examples/aDir");
   IO.Put ("New default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   D.Create_Directory (New_Directory => "some_dir");
   if D.Exists (Name => "some_dir") then
      IO.Put_Line ("some_dir exists.");
   end if;
   D.Delete_Directory (Directory => "some_dir");
 
   D.Create_Directory (New_Directory => "some_dir2");
   if D.Exists (Name => "some_dir2") then
      IO.Put_Line ("some_dir2 exists.");
   end if;
   D.Delete_Directory (Directory => "/home/thomas/wiki_examples/aDir/some_dir2");
end Adir;
with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   Delete_Non_Existing :
   declare
   begin
      D.Delete_Directory (Directory => "does_not_exist");  
   exception
      when D.Name_Error =>
         IO.Put_Line (Item => "Directory not found.");
   end Delete_Non_Existing;
 
   Delete_With_Contents :
   declare  
   begin
      D.Delete_Directory (Directory => "dir_with_contents");    
   exception
      when D.Use_Error =>
         IO.Put_Line (Item => "Cannot delete non-empty directory.");
   end Delete_With_Contents;
end aDir;


Create_Path

[编辑 | 编辑源代码]

Create_Path 的规范如下所示

procedure Create_Path
  (New_Directory : String;
   Form          : String := "");

使用 Create_Path,可以创建嵌套目录,即使父目录不存在也是如此。这就像发出 mkdir -p /some/path/to/new/dir 命令,其中创建了整个路径,一直到 dir 目录。

与它的兄弟 Create_Directory 一样,Form 参数用于实现特定特性。空字符串指定使用实现创建新目录的默认选项。

要创建 this/is/a/new/directory 目录,我们只需在 aDir 程序中添加以下内容

D.Create_Path (New_Directory => "this/is/a/new/directory");
if D.Exists (Name => "this/is/a/new/directory") then
   IO.Put_Line (Item => "this/is/a/new/directory exists!");
end if;

输出为

 Starting default directory: /home/thomas/wiki_examples/aDir
 this/is/a/new/directory exists!

如果调用 Create_Path 时路径已经存在,则该过程什么也不做。

Create_Path 相对于当前默认目录工作,除非给定的 Directory 描述了从文件系统根目录开始的路径,例如,*nix 系统的 / 和 Windows 系统的 c:/。要创建 /tmp 中的 this/is/a/new/directory,我们只需在 Directory 字符串中添加 /tmp

D.Create_Path (New_Directory => "/tmp/this/is/a/new/directory");
if D.Exists (Name => "/tmp/this/is/a/new/directory") then
   IO.Put_Line (Item => "/tmp/this/is/a/new/directory exists!");
end if;

因此,如果路径是相对的,则当前默认目录用作基目录,但如果路径是绝对的,则忽略当前默认目录,并完全根据参数创建路径。

两个异常 Name_ErrorUse_Error 在与 Create_Directory 相同的情况下引发:如果 New_Directory 字符串未标识目录,则引发 Name_Error;如果程序无法创建任何一个目录,例如由于权限问题,则引发 Use_Error

Ada.Directories.Create_Path 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   D.Create_Path (New_Directory => "this/is/a/new/directory");
   if D.Exists (Name => "this/is/a/new/directory") then
      IO.Put_Line (Item => "this/is/a/new/directory exists!");
   end if;
end aDir;

Delete_Tree

[编辑 | 编辑源代码]

Delete_Tree 的规范如下所示

procedure Delete_Tree (Directory : String);

Delete_Tree 使我们能够一举删除目录及其内容,因此,如果我们继续使用 Create_Path 中的示例,我们可以通过将以下内容添加到程序中来删除 this/is/a/new/directory

D.Delete_Tree (Directory => "this/");
if not D.Exists (Name => "this/") then
   IO.Put_Line (Item => "this/is/a/new/directory does NOT exist!");
end if;

输出为

 Starting default directory: /home/thomas/wiki_examples/aDir
 this/is/a/new/directory exists!
 this/is/a/new/directory does NOT exist!

两个异常 Name_ErrorUse_Error 也对我们可用。它们按预期工作,如果 Directory 不存在,则会引发 Name_Error;如果 Directory 因某种原因而无法删除,则会引发 Use_Error。RM 中有一条关于此行为的重要说明

如果外部环境不支持使用给定名称删除目录或其内容的一部分(在没有 Name_Error 的情况下),则会传播 Use_Error 异常。如果传播了 Use_Error,则未指定是否删除了目录内容的一部分。

重要的是要特别注意最后一句话:未指定是否删除了目录内容的一部分

这意味着可能会引发 Use_Error,但这并不一定意味着目录及其内容 100% 完好无损。其中一部分很可能已被删除。

最后,应该提到的是,Delete_Tree 在当前默认目录中查找 Directory,除非给定了绝对路径。

Ada.Directories.Delete_Tree 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   D.Create_Path (New_Directory => "this/is/a/new/directory");
   if D.Exists (Name => "this/is/a/new/directory") then
      IO.Put_Line (Item => "this/is/a/new/directory exists!");
   end if;
 
   D.Delete_Tree (Directory => "this/");
   if not D.Exists (Name => "this/") then
      IO.Put_Line (Item => "this/is/a/new/directory does NOT exist!");
   end if;
end aDir;

Delete_File

[编辑 | 编辑源代码]

Delete_File 的规范如下所示

procedure Delete_File (Name : String);

Delete_File 的工作方式与 Delete_Directory 非常相似,只是它删除文件而不是目录。在 Ada.Directories 的上下文中,文件可以是普通文件或特殊文件

外部文件可分类为目录、特殊文件或普通文件。目录是外部文件,它是目标系统上文件的容器。特殊文件是外部文件,无法通过预定义的 Ada 输入输出包来创建或读取。不是特殊文件或目录的外部文件称为普通文件。

通常的异常也适用于 Delete_File

让我们创建一个新文件

 $ touch some_file

现在将此添加到基本 aDir 程序中

if D.Exists (Name => "some_file") then
   IO.Put_Line (Item => "some_file exists");   
end if;
   
D.Delete_File (Name => "some_file");
   
if not D.Exists (Name => "some_file") then
   IO.Put_Line (Item => "some_file does NOT exist");   
end if;

输出为

 Starting default directory: /home/thomas/wiki_examples/aDir
 some_file exists
 some_file does NOT exist

some_file 文件不见了。

以下是一个示例,其中我们(A)没有删除 `some_file` 文件的权限,并且(B)尝试删除一个不存在的文件。

if D.Exists (Name => "some_file") then
   IO.Put_Line (Item => "some_file exists");   
end if;
   
declare
begin
   D.Delete_File (Name => "some_file");
exception
   when D.Use_Error =>
      IO.Put_Line (Item => "Cannot delete some_file");
end;
   
declare
begin
   D.Delete_File (Name => "some_wrong_filename");
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "File does not exist");
end;
   
if D.Exists (Name => "some_file") then
   IO.Put_Line (Item => "some_file still exists");   
end if;

输出应该像这样

 Starting default directory: /home/thomas/wiki_examples/aDir
 some_file exists
 Cannot delete some_file
 File does not exist
 some_file still exists

至此,我们完成了对 `Delete_File` 的介绍。


Ada.Directories.Delete_File 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   if D.Exists (Name => "some_file") then
      IO.Put_Line (Item => "some_file exists");   
   end if;
 
   D.Delete_File (Name => "some_file");
 
   if not D.Exists (Name => "some_file") then
      IO.Put_Line (Item => "some_file does NOT exist");   
   end if;
end aDir;
with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   if D.Exists (Name => "some_file") then
      IO.Put_Line (Item => "some_file exists");   
   end if;
 
   declare
   begin
      D.Delete_File (Name => "some_file");
   exception
      when D.Use_Error =>
         IO.Put_Line (Item => "Cannot delete some_file");
   end;
 
   declare
   begin
      D.Delete_File (Name => "some_wrong_filename");
   exception
      when D.Name_Error =>
         IO.Put_Line (Item => "File does not exist");
   end;
 
   if D.Exists (Name => "some_file") then
      IO.Put_Line (Item => "some_file still exists");   
   end if;
end aDir;

重命名

[编辑 | 编辑源代码]

`Rename` 的规范如下所示

procedure Rename (Old_Name, New_Name : String);

`Rename` 过程重命名目录和文件,前提是 `New_Name` 不存在。如果 `Old_Name` 不匹配目录或文件,则会引发 `Name_Error` 异常,如果无法重命名目录/文件,则会引发 `Use_Error` 异常。在以下示例中,我们将假设存在目录 `some_dir` 和文件 `some_file`。

首先,我们将向 `aDir` 程序的声明部分添加一个过程

procedure Do_We_Exist (A_Name : String) is
begin
   if D.Exists (Name => A_Name) then
      IO.Put_Line (Item => "Yes, " & A_Name & " exists");
   else 
      IO.Put_Line (Item => "No, " & A_Name & " does not exist");
   end if;
end Do_We_Exist;

此过程只是程序中的一点糖。它主要用于避免重复使用 `if` 块。

接下来,我们将向程序主体添加几行代码

Do_We_Exist (A_Name => "some_new_dir"); 
Do_We_Exist (A_Name => "some_new_file");
   
D.Rename (Old_Name => "some_dir",
          New_Name => "some_new_dir");
D.Rename (Old_Name => "some_file",
          New_Name => "some_new_file");
   
Do_We_Exist (A_Name => "some_new_dir"); 
Do_We_Exist (A_Name => "some_new_file");
   
D.Rename (Old_Name => "some_new_dir",
          New_Name => "some_dir");
D.Rename (Old_Name => "some_new_file",
          New_Name => "some_file");

此操作的输出为

 Starting default directory: /home/thomas/wiki_examples/aDir
 No, some_new_dir does not exist
 No, some_new_file does not exist
 Yes, some_new_dir exists
 Yes, some_new_file exists

重命名文件和目录从未如此简单。

Ada.Directories.Rename 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
 
   procedure Do_We_Exist (A_Name : String) is
   begin
      if D.Exists (Name => A_Name) then
         IO.Put_Line (Item => "Yes, " & A_Name & " exists");
      else 
         IO.Put_Line (Item => "No, " & A_Name & " does not exist");
      end if;
   end Do_We_Exist;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   Do_We_Exist (A_Name => "some_new_dir"); 
   Do_We_Exist (A_Name => "some_new_file");
 
   D.Rename (Old_Name => "some_dir",
             New_Name => "some_new_dir");
   D.Rename (Old_Name => "some_file",
             New_Name => "some_new_file");
 
   Do_We_Exist (A_Name => "some_new_dir"); 
   Do_We_Exist (A_Name => "some_new_file");
 
   D.Rename (Old_Name => "some_new_dir",
             New_Name => "some_dir");
   D.Rename (Old_Name => "some_new_file",
             New_Name => "some_file");
end aDir;

复制文件

[编辑 | 编辑源代码]

`Copy_File` 的规范如下所示

procedure Copy_File
  (Source_Name   : String;
   Target_Name   : String;
   Form          : String := "");

`Copy_File` 将现有文件 `Source_Name` 的内容复制到名为 `Target_Name` 的新文件。结果是源文件的副本。`Copy_File` 不复制目录。仅复制普通文件。如前所述,`Form` 参数仅在实现需要时使用。以下是 RM 对 `Form` 的描述

Form 参数可用于指定结果外部文件的系统相关特性;Form 参数的解释由实现定义。

要将 `some_file` 复制到 `some_new_file`,我们只需将以下行添加到 `aDir` 程序的主体中即可

D.Copy_File (Source_Name => "some_file",
             Target_Name => "some_new_file");

请注意,如果 `some_new_file` 已经存在,它将被覆盖。通常的异常 `Name_Error` 和 `Use_Error` 也适用于 `Copy_File`

declare
begin
   D.Copy_File (Source_Name => "some_non_existant_file",
                Target_Name => "");
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Source and/or Target Name_Error");
end;
   
declare
begin
   D.Copy_File (Source_Name => "some_file",
                Target_Name => "/root/illegal_file_location");
exception
   when D.Use_Error =>
      IO.Put_Line (Item => "Source and/or Target Use_Error");
end;

如果 `Source_Name` 或 `Target_Name` 未正确标识文件,则会引发 `Name_Error` 异常。如果操作失败,则会引发 `Use_Error` 异常;文件存在,但由于其他原因,无法复制。


Ada.Directories.Copy_File 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
 
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   D.Copy_File (Source_Name => "some_file",
                Target_Name => "some_new_file");
end aDir;
with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
 
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   declare
   begin
      D.Copy_File (Source_Name => "some_non_existant_file",
                   Target_Name => "");
   exception
      when D.Name_Error =>
         IO.Put_Line (Item => "Source and/or Target Name_Error");
   end;
 
   declare
   begin
      D.Copy_File (Source_Name => "some_file",
                   Target_Name => "/root/illegal_file_location");
   exception
      when D.Use_Error =>
         IO.Put_Line (Item => "Source and/or Target Use_Error");
   end;
end aDir;

名称操作

[编辑 | 编辑源代码]

以下六个函数不与文件系统交互。它们只是操作字符串。有了这些函数,我们可以构建文件路径字符串、从路径中提取文件名、提取文件扩展名以及发现包含文件的目录名称。

Full_Name

[编辑 | 编辑源代码]

`Full_Name` 的规范如下所示

function Full_Name (Name : String) return String;

`Full_Name` 返回给定 `Name` 的完整路径。`Name` 参数可以是单个文件名、文件的相对路径或绝对路径。`Full_Name` 不关心文件是否实际存在。它只关心返回正确的完整路径。RM 对此的描述如下

返回对应于 Name 指定的文件名的完整名称。如果作为 Name 给定的字符串不允许识别外部文件(包括目录和特殊文件),则会传播 Name_Error 异常。

当我第一次阅读这句话时,我认为这句话 **如果作为 Name 给定的字符串不允许识别外部文件,则会传播 Name_Error 异常** 意味着如果给定的 `Name` 参数无法解析为实际存在的文件,则会引发 `Name_Error` 异常。然而,事实并非如此。相反,这意味着如果 `Name` 格式错误,则会引发 `Name_Error` 异常。

让我们看看它是如何工作的

IO.Put_Line (Item => D.Full_Name (Name => "foo"));
IO.Put_Line (Item => D.Full_Name (Name => "foo/bar"));
IO.Put_Line (Item => D.Full_Name (Name => "/home/thomas/stuff"));
   
D.Set_Directory (Directory => "/tmp");
   
IO.Put_Line (Item => D.Full_Name (Name => "foo"));
IO.Put_Line (Item => D.Full_Name (Name => "foo/bar"));
IO.Put_Line (Item => D.Full_Name (Name => "/home/thomas/stuff"));

IO.Put_Line (Item => D.Full_Name (Name => ""));
   --  Malformed Name parameter
   
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name parameter is malformed");

以及生成的输出

 Starting default directory: /home/thomas/wiki_examples/aDir
 /home/thomas/wiki_examples/aDir/foo
 /home/thomas/wiki_examples/aDir/foo/bar
 /home/thomas/stuff
 New default directory: /tmp
 /tmp/foo
 /tmp/foo/bar
 /home/thomas/stuff
 Name parameter is malformed

与所有其他依赖于当前默认目录的函数和过程一样,如果 `Name` 是相对路径,则将 `Name` 参数附加到当前默认目录,而如果 `Name` 是绝对路径,则会忽略当前默认目录。

Ada.Directories.Full_Name 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
 
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   IO.Put_Line (Item => D.Full_Name (Name => "foo"));
   IO.Put_Line (Item => D.Full_Name (Name => "foo/bar"));
   IO.Put_Line (Item => D.Full_Name (Name => "/home/thomas/stuff"));
 
   D.Set_Directory (Directory => "/tmp");
   IO.Put ("New default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   IO.Put_Line (Item => D.Full_Name (Name => "foo"));
   IO.Put_Line (Item => D.Full_Name (Name => "foo/bar"));
   IO.Put_Line (Item => D.Full_Name (Name => "/home/thomas/stuff"));
 
   IO.Put_Line (Item => D.Full_Name (Name => ""));
   --  Malformed Name parameter
 
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name parameter is malformed");
end aDir;

Simple_Name

[编辑 | 编辑源代码]

`Simple_Name` 的规范如下所示

function Simple_Name (Name : String) return String;

在 `Full_Name` 返回文件的完整路径的情况下,`Simple_Name` 返回路径的简单名称组件。因此,对于 `Name` 参数 `/home/thomas/foo`,它将返回 `foo`。`Name_Error` 异常仅在 `Name` 格式错误时引发。让我们看一个示例

IO.Put_Line (Item => D.Simple_Name (Name => "foo"));
IO.Put_Line (Item => D.Simple_Name (Name => "foo/bar"));
IO.Put_Line (Item => D.Simple_Name (Name => "/home/thomas/stuff"));
   
IO.Put_Line (Item => D.Simple_Name (Name => ""));
--  Malformed Name parameter
   
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name parameter is malformed");
end aDir;

输出为

 Starting default directory: /home/thomas/wiki_examples/aDir
 foo
 bar
 stuff
 Name parameter is malformed

非常方便。


Ada.Directories.Simple_Name 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
 
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   IO.Put_Line (Item => D.Simple_Name (Name => "foo"));
   IO.Put_Line (Item => D.Simple_Name (Name => "foo/bar"));
   IO.Put_Line (Item => D.Simple_Name (Name => "/home/thomas/stuff"));
 
   IO.Put_Line (Item => D.Simple_Name (Name => ""));
   --  Malformed Name parameter
 
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name parameter is malformed");
end aDir;

Containing_Directory

[编辑 | 编辑源代码]

`Containing_Directory` 的规范如下所示

function Containing_Directory (Name : String) return String;

`Containing_Directory` 删除给定 `Name` 路径的简单名称。让我们看看它是如何工作的

IO.Put_Line (Item => D.Containing_Directory (Name => "foo"));
IO.Put_Line (Item => D.Containing_Directory (Name => "foo/bar"));
IO.Put_Line (Item => D.Containing_Directory (Name => "/home/thomas/stuff"));
   
declare
begin
   IO.Put_Line (Item => D.Containing_Directory (Name => ""));
   --  Malformed Name parameter
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name_Error raised. Malformed Name.");
end;
   
declare
begin
   IO.Put_Line (Item => D.Containing_Directory (Name => "/"));
   --  No parent directory
exception
   when D.Use_Error =>
      IO.Put_Line (Item => "Use_Error raised. No containing directory.");
end;

输出为

 Starting default directory: /home/thomas/wiki_examples/aDir
 /home/thomas/wiki_examples/aDir
 foo
 /home/thomas
 Name_Error raised. Malformed Name.
 Use_Error raised. No containing directory.

如预期的那样。请注意,`Use_Error` 异常仅在给定的 `Name` 参数没有包含目录时引发。

Ada.Directories.Containing_Directory 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
 
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   IO.Put_Line (Item => D.Containing_Directory (Name => "foo"));
   IO.Put_Line (Item => D.Containing_Directory (Name => "foo/bar"));
   IO.Put_Line (Item => D.Containing_Directory (Name => "/home/thomas/stuff"));
 
   declare
   begin
      IO.Put_Line (Item => D.Containing_Directory (Name => ""));
      --  Malformed Name parameter
   exception
      when D.Name_Error =>
         IO.Put_Line (Item => "Name_Error raised. Malformed Name.");
   end;
 
   declare
   begin
      IO.Put_Line (Item => D.Containing_Directory (Name => "/"));
      --  No parent directory
   exception
      when D.Use_Error =>
         IO.Put_Line (Item => "Use_Error raised. No containing directory.");
   end;
end aDir;

Extension

[编辑 | 编辑源代码]

`Extension` 的规范如下所示

function Extension (Name : String) return String;

如果你想提取文件的扩展名,这个函数就是你需要的东西。以下是一个使用示例

IO.Put_Line (Item => D.Extension (Name => "foo.txt"));
IO.Put_Line (Item => D.Extension (Name => "foo/bar"));
IO.Put_Line (Item => D.Extension (Name => "/home/thomas/stuff.conf"));
   
IO.Put_Line (Item => D.Extension (Name => ""));
   --  Malformed Name parameter
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name_Error raised. Malformed Name.");

以及输出

 Starting default directory: /home/thomas/wiki_examples/aDir
 txt
  
 conf
 Name_Error raised. Malformed Name.

如你所见,如果没有扩展名(foo/bar 行),则返回空字符串。当 `Name` 参数格式错误时,会引发 `Name_Error` 异常。


Ada.Directories.Extension 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
 
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   IO.Put_Line (Item => D.Extension (Name => "foo.txt"));
   IO.Put_Line (Item => D.Extension (Name => "foo/bar"));
   IO.Put_Line (Item => D.Extension (Name => "/home/thomas/stuff.conf"));
 
   IO.Put_Line (Item => D.Extension (Name => ""));
      --  Malformed Name parameter
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name_Error raised. Malformed Name.");
end aDir;

Base_Name

[编辑 | 编辑源代码]

`Base_Name` 的规范如下所示

function Base_Name (Name : String) return String;

我确信你已经猜到 `Base_Name` 的作用了,但还是让我解释一下示例代码

IO.Put_Line (Item => D.Base_Name (Name => "foo.txt"));
IO.Put_Line (Item => D.Base_Name (Name => ".secret"));
IO.Put_Line (Item => D.Base_Name (Name => ".secret.conf"));
IO.Put_Line (Item => D.Base_Name (Name => "foo/bar"));
IO.Put_Line (Item => D.Base_Name (Name => "/home/thomas/stuff.conf"));
   
IO.Put_Line (Item => D.Base_Name (Name => ""));
   --  Malformed Name parameter
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name_Error raised. Malformed Name.");

输出

 Starting default directory: /home/thomas/wiki_examples/aDir
 foo
 
 .secret
 bar
 stuff
 Name_Error raised. Malformed Name.

请注意关于 `.secret` 文件的“奇怪”行为。它没有返回完整的 `.secret` 字符串(实际上是文件的基名),我们只得到了一个空字符串。这可能被认为有点奇怪,但它符合 `Base_Name` 编程人员的意图。以下是来自实际 `Base_Name` 函数的注释

--  Look for the last dot in the file name and return the part of the
--  file name preceding this last dot. If the first dot is the first
--  character of the file name, the base name is the empty string.

所以我们从源头上得到了答案:如果 `Base_Name` 返回空字符串,你可能正在处理一个点文件,你将不得不手动解析它。因此,你不能期望 `Base_Name` 返回与例如标准 GNU 工具 `basename` 相同的结果。`Base_Name` 必须在多个平台上可靠地工作,因此作者必须决定一个通用的、可预测的、方法。对于点文件返回空字符串就是这样,可预测。


Ada.Directories.Base_Name 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
 
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   IO.Put_Line (Item => D.Base_Name (Name => "foo.txt"));
   IO.Put_Line (Item => D.Base_Name (Name => ".secret"));
   IO.Put_Line (Item => D.Base_Name (Name => ".secret.conf"));
   IO.Put_Line (Item => D.Base_Name (Name => "foo/bar"));
   IO.Put_Line (Item => D.Base_Name (Name => "/home/thomas/stuff.conf"));   
 
   IO.Put_Line (Item => D.Base_Name (Name => ""));
      --  Malformed Name parameter
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name_Error raised. Malformed Name.");
end aDir;

`Compose` 的规范如下所示

function Compose
     (Containing_Directory : String := "";
      Name                 : String;
      Extension            : String := "") return String;

`Compose` 允许我们从目录路径、简单名称和扩展名构建字符串。会进行一些基本检查以确保生成的字符串在语法上是正确的。`Compose` 不关心生成的路径是否实际存在,它只关心它作为文件完整名称的有效性。

让我们看看它是如何工作的

IO.Put_Line (Item => D.Compose (Containing_Directory => "foo/",
                                Name                 => "bar",
                                Extension            => "conf"));
IO.Put_Line (Item => D.Compose (Containing_Directory => "",
                                Name                 => "bar",
                                Extension            => "conf"));
IO.Put_Line (Item => D.Compose (Containing_Directory => "/foo",
                                Name                 => "bar",
                                Extension            => ""));
IO.Put_Line (Item => D.Compose (Containing_Directory => "/foo",
                                Name                 => "bar.conf",
                                Extension            => ""));
IO.Put_Line (Item => D.Compose (Containing_Directory => "/foo",
                                Name                 => "",
                                Extension            => "conf"));
IO.Put_Line (Item => D.Compose (Containing_Directory => "",
                                Name                 => "",
                                Extension            => "conf"));
 
IO.Put_Line (Item => D.Compose (Containing_Directory => "foo/",
                                Name                 => "",
                                Extension            => ""));
--  Force Name_Error by omitting Name and Extension
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name_Error raised.");

以上操作的输出为

 Starting default directory: /home/thomas/wiki_examples/aDir
 foo/bar.conf
 bar.conf
 /foo/bar
 /foo/bar.conf
 /foo/.conf
 .conf
 Name_Error raised. Malformed Name.

这并不奇怪。

当发生以下情况时,会引发 `Name_Error` 异常

如果作为 Containing_Directory 给定的字符串不为空且不允许识别目录,或者如果作为 Extension 给定的字符串不为空且不是可能的扩展名,或者如果作为 Name 给定的字符串不是可能的简单名称(如果 Extension 为空)或基名(如果 Extension 不为空),则会传播 Name_Error 异常。

`Compose` 在构建指向文件的字符串路径时非常方便。它比你自己连接字符串要好得多。


Ada.Directories.Compose 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
 
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   IO.Put_Line (Item => D.Compose (Containing_Directory => "foo/",
                                   Name                 => "bar",
                                   Extension            => "conf"));
   IO.Put_Line (Item => D.Compose (Containing_Directory => "",
                                   Name                 => "bar",
                                   Extension            => "conf"));
   IO.Put_Line (Item => D.Compose (Containing_Directory => "/foo",
                                   Name                 => "bar",
                                   Extension            => ""));
   IO.Put_Line (Item => D.Compose (Containing_Directory => "/foo",
                                   Name                 => "bar.conf",
                                   Extension            => ""));
   IO.Put_Line (Item => D.Compose (Containing_Directory => "/foo",
                                   Name                 => "",
                                   Extension            => "conf"));
   IO.Put_Line (Item => D.Compose (Containing_Directory => "",
                                   Name                 => "",
                                   Extension            => "conf"));
 
   IO.Put_Line (Item => D.Compose (Containing_Directory => "foo/",
                                   Name                 => "",
                                   Extension            => ""));
   --  Force Name_Error by omitting Name and Extension
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name_Error raised.");
end aDir;

文件和目录查询

[编辑 | 编辑源代码]

以下函数的目的很明显。例如 `Exists`、`Kind`、`Size` 和 `Modification_Time` 这样的名称,应该很容易猜到这些函数的作用,因此,我们毫不犹豫地开始吧。

`Exists` 的规范如下所示

function Exists (Name : String) return Boolean;

如果你想知道文件或目录是否存在,你应该使用 `Exists`。我们已经在一些前面的示例中看到了 `Exists` 的实际应用,但让我们再看一个代码片段,其中 `Exists` 是主角

if D.Exists (Name => "some_file") then
   IO.Put_Line (Item => "some_file exists");
end if;
   
if D.Exists (Name => "/home/thomas/wiki_examples/aDir/some_dir") then
   IO.Put_Line (Item => "/home/thomas/wiki_examples/aDir/some_dir exists");
end if;
   
if not D.Exists (Name => "nonexistant_file") then
   IO.Put_Line (Item => "nonexistant_file does not exist");
end if;
   
if D.Exists (Name => "") then
   IO.Put_Line (Item => "This is impossible!");
end if;
   
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name_Error raised");

以及输出

 Starting default directory: /home/thomas/wiki_examples/aDir
 some_file exists
 /home/thomas/wiki_examples/aDir/some_dir exists
 nonexistant_file does not exist
 Name_Error raised

如你所见,如果给定的是相对路径,则会考虑当前默认目录,如果给定的 `Name` 无效(既不是文件也不是目录),则会引发 `Name_Error` 异常,就像上面示例中的空字符串一样。除此之外,关于此函数就没有什么好说的了。

Ada.Directories.Exists 示例源代码

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   if D.Exists (Name => "some_file") then
      IO.Put_Line (Item => "some_file exists");
   end if;
 
   if D.Exists (Name => "/home/thomas/wiki_examples/aDir/some_dir") then
      IO.Put_Line (Item => "/home/thomas/wiki_examples/aDir/some_dir exists");
   end if;
 
   if not D.Exists (Name => "nonexistant_file") then
      IO.Put_Line (Item => "nonexistant_file does not exist");
   end if;
 
   if D.Exists (Name => "") then
      IO.Put_Line (Item => "This is impossible!");
   end if;
 
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name_Error raised");
end aDir;

Kind 的规范如下所示

function Kind (Name : String) return File_Kind;

Ada.Directories 中,文件/目录被分类为三种可能的“文件类型”:DIRECTORYSPECIAL_FILEORDINARY_FILEDIRECTORY 是一个包含其他文件的目录。SPECIAL_FILE 是一个不能被预定义的 Ada 输入输出包读取或创建的文件。一个既不是 DIRECTORY 也不是 SPECIAL_FILE 的文件就是 ORDINARY_FILE

让我们看看它是如何工作的。首先,我们必须在 aDir 程序的声明部分添加一行代码

package IOE is new Ada.Text_IO.Enumeration_IO (D.File_Kind);

然后是主体

IOE.Put (Item => D.Kind (Name => "some_file"));
IO.New_Line;
IOE.Put (Item => D.Kind (Name => "some_dir"));
IO.New_Line;
IOE.Put (Item => D.Kind (Name => "/dev/sda"));
IO.New_Line;
IOE.Put (Item => D.Kind (Name => ""));
   
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name_Error raised");

以及输出

 Starting default directory: /home/thomas/wiki_examples/aDir
 ORDINARY_FILE
 DIRECTORY
 SPECIAL_FILE
 Name_Error raised

Kind 遵循当前默认目录,就像 Ada.Directories 中的所有其他函数和过程一样。如果给定的 Name 参数无效,则会引发 Name_Error

{{collapsible box|title=Ada.Directories.Kind 示例源代码|collapsed=yes|content=

with Ada.Text_IO; 
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
   package IOE is new Ada.Text_IO.Enumeration_IO (D.File_Kind);
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   IOE.Put (Item => D.Kind (Name => "some_file"));
   IO.New_Line;
   IOE.Put (Item => D.Kind (Name => "some_dir"));
   IO.New_Line;
   IOE.Put (Item => D.Kind (Name => "/dev/sda"));
   IO.New_Line;
   IOE.Put (Item => D.Kind (Name => ""));
 
exception
   when D.Name_Error =>
      IO.Put_Line (Item => "Name_Error raised");
end aDir;


Size 的规范如下所示

function Size (Name : String) return File_Size;

Size 返回的 File_Size 类型是一个整数,其范围为 0 .. Long_Long_Integer'Last。也就是说,在大多数系统上,这是一个非常大的数字。需要注意的是,Size 的作用完全符合预期

IO.Put_Line (Item => D.Size (Name => "some_file")'Img);
IO.Put_Line (Item => D.Size (Name => "adir")'Img);
IO.Put_Line 
  (Item => "Max File_Size on this system: " & Long_Long_Integer'Last'Img);

结果是

 Starting default directory: /home/thomas/wiki_examples/aDir
  7
  578580
 Max File_Size on this system:  9223372036854775807

返回的大小是文件中包含的流元素数量,在本例中是 7 个和 578580 字节。数字 9223372036854775807 旨在向您展示 File_Size 类型可以处理的数字有多大。我认为我们很难找到能够处理如此大文件的操作系统或文件系统。请注意,Long_Long_Integer 是实现相关的:它可能在您的系统上完全不同。

通常的 Name_Error 异常适用于 Size,并且如果文件大小不是 File_Size 类型,您还会发现一个 Constraint_Error,即它低于 0 或高于 Long_Long_Integer'Last

{{collapsible box|title=Ada.Directories.Size 示例源代码|collapsed=yes|content=

with Ada.Text_IO;
with Ada.Directories;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   IO.Put_Line (Item => D.Size (Name => "some_file")'Img);
   IO.Put_Line (Item => D.Size (Name => "adir")'Img);
   IO.Put_Line 
     (Item => "Max File_Size on this system: " & Long_Long_Integer'Last'Img);
end aDir;


Modification_Time

[编辑 | 编辑源代码]

Modification_Time 的规范如下所示

function Modification_Time (Name : String) return Ada.Calendar.Time;

如果您需要知道文件上次修改的时间,此函数可以满足您的需求。如您所见,它返回一个 Ada.Calendar.Time 对象,因此为了实际查看输出,我们需要添加一个 with 子句和一行额外的代码到 aDir 的声明部分。首先是 with 子句

with Ada.Calendar.Formatting;

然后是声明

package ACF renames Ada.Calendar.Formatting;

最后是添加到主体中的代码

IO.Put_Line (Item => ACF.Image (D.Modification_Time (Name => "some_file")));

这段代码片段的输出是

 Starting default directory: /home/thomas/wiki_examples/aDir
 2009-10-06 14:10:04

如果文件无效,则会引发通常的 Name_Error,如果环境不支持文件修改时间的概念,则会引发 Use_Error

{{collapsible box|title=Ada.Directories.Modification_Time 示例源代码|collapsed=yes|content=

with Ada.Text_IO;
with Ada.Directories;
with Ada.Calendar.Formatting;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
   package ACF renames Ada.Calendar.Formatting;
begin
   IO.Put ("Starting default directory: ");
   IO.Put_Line (Item => D.Current_Directory);
 
   IO.Put_Line (Item => ACF.Image (D.Modification_Time (Name => "some_file")));
end aDir;


目录搜索

[编辑 | 编辑源代码]

使用以下类型和子程序可以搜索目录结构。在前面的部分中,我们并没有真正关注类型,因为它们在使用函数和过程时没有发挥积极作用,但对于搜索来说,情况有所不同:在这里,我们积极地使用类型来跟踪搜索的状态和搜索的结果。

可以使用活动迭代器或被动迭代器进行搜索。活动迭代器方法只是一个简单的循环,而被动迭代器方法使用指向子程序的访问,该子程序定义了对搜索的每个结果的操作。我们将展示两种方法的工作方式。

Directory_Entry_Type

[编辑 | 编辑源代码]

Directory_Entry_Type 的规范如下所示

type Directory_Entry_Type is limited private;

private
  type Directory_Entry_Type is record
     Is_Valid : Boolean := False;
     Simple   : Ada.Strings.Unbounded.Unbounded_String;
     Full     : Ada.Strings.Unbounded.Unbounded_String;
     Kind     : File_Kind := Ordinary_File;
  end record;

Directory_Entry_Type 表示目录中的单个条目。创建 Directory_Entry_Type 的唯一方法是使用 Get_Next_Entry 过程。然后,可以使用适当的子程序(例如 Simple_NameKind 等)来使用这样的 Directory_Entry_Type 对象。从 Directory_Entry_Type 记录中可以明显地看出我们可以从中提取哪些信息。

Filter_Type

[编辑 | 编辑源代码]

Filter_Type 的规范如下所示

type Filter_Type is array (File_Kind) of Boolean;

Ada.Directories 中有三种不同的文件类型:DirectoryOrdinary_FileSpecial_File。使用 Filter_Type,您可以定义要搜索的这些文件类型中的哪一种

Filter : Filter_Type := (Ordinary_File => True,
                         Special_File => False,
                         Directory => True);

在这里,我们设置了一个过滤器,它忽略 Special_File,并允许 Ordinary_FileDirectory

Search_Type

[编辑 | 编辑源代码]

Search_Type 的规范如下所示

type Search_Type is limited private;'

type Search_Data;
type Search_Ptr is access Search_Data;

private
   type Search_Type is new Ada.Finalization.Controlled with record
      Value : Search_Ptr;
   end record;

Search_Type 包含搜索的状态。您可以使用 Start_Search 初始化 Search_Type 对象,使用 More_Entries 检查它,使用 Get_Next_Entry 读取它,并使用 End_Search 清理它。

[编辑 | 编辑源代码]

Start_Search 的规范如下所示

procedure Start_Search
  (Search    : in out Search_Type;
   Directory : String;
   Pattern   : String;
   Filter    : Filter_Type := (others => True));

所有与搜索相关的类型和子程序都高度依赖于彼此。因此,我认为将所有这些都包含在一个完整的程序中,将是最有意义的。这意味着我们将偏离通常的 aDir 程序,而是使用这个

with Ada.Text_IO;
with Ada.Directories; use Ada.Directories;
with Ada.Calendar.Formatting;

procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
   package IOI is new IO.Integer_IO (D.File_Size);
   package ACF renames Ada.Calendar.Formatting;

   A_Search : D.Search_Type;
   Search_Item : D.Directory_Entry_Type;
   Filter : constant D.Filter_Type := (D.Ordinary_File => True,
                                       D.Special_File => False,
                                       D.Directory => True);
begin
   D.Start_Search (Search    => A_Search,
                   Directory => D.Current_Directory,
                   Pattern   => "",
                   Filter    => Filter);
   while D.More_Entries (Search => A_Search) loop
      D.Get_Next_Entry (Search          => A_Search,
                        Directory_Entry => Search_Item);
      IO.Put (Item => D.Simple_Name (Directory_Entry => Search_Item));
      IO.Set_Col (To => 25);
      if D.Kind (Directory_Entry => Search_Item) = D.Ordinary_File then
         IOI.Put (Item  => D.Size (Directory_Entry => Search_Item),
                  Width => 1);
         IO.Put (Item => " bytes");
      else
         IO.Put (Item => "dir");
      end if;
      IO.Set_Col (To => 45);
      IO.Put (Item => ACF.Image
              (D.Modification_Time (Directory_Entry => Search_Item)));
      IO.Set_Col (To => 70);
      IO.Put (Item => D.Full_Name (Directory_Entry => Search_Item));
      IO.New_Line;
   end loop;
   D.End_Search (Search => A_Search);
end aDir;

该程序在我的系统上运行时的输出为

 /home/thomas/wiki_examples/aDir/adir
 .                       dir                 2009-10-23 20:17:22      /home/thomas/wiki_examples/aDir/.
 ..                      dir                 2009-09-24 20:07:57      /home/thomas/wiki_examples/aDir/..
 objects                 dir                 2009-10-27 20:56:32      /home/thomas/wiki_examples/aDir/objects
 Proj.gpr                502 bytes           2009-09-24 20:09:20      /home/thomas/wiki_examples/aDir/Proj.gpr
 adir                    594193 bytes        2009-10-23 20:17:22      /home/thomas/wiki_examples/aDir/adir
 some_dir                dir                 2009-10-06 14:10:25      /home/thomas/wiki_examples/aDir/some_dir
 adir.adb                1781 bytes          2009-10-23 20:17:21      /home/thomas/wiki_examples/aDir/adir.adb
 some_file               7 bytes             2009-10-06 14:10:04      /home/thomas/wiki_examples/aDir/some_file
 some_new_file           7 bytes             2009-10-06 14:37:15      /home/thomas/wiki_examples/aDir/some_new_file

Start_Search 为搜索设置了舞台。它接受四个参数:Search,它包含搜索的状态;Directory,它是要搜索的目录;Pattern,它是用于匹配文件名的模式;以及 Filter,它定义了搜索返回的文件类型。

Pattern 值的解释是实现相关的,但空字符串等于“匹配所有内容”。很有可能简单的、众所周知的模式(例如 *.txt)会产生预期的结果:所有扩展名为 .txt 的文件都将匹配。

在本例中,我们搜索当前目录中所有不是 Special_File(Filter 被分配为 D.Special_File => False)的内容(空 Pattern 字符串)。

上面的程序使用了一个活动迭代器:while 循环。如您所见,只要 D.More_Entries (Search => A_Search)True,此循环就会继续。当不再满足该条件时,循环结束,我们调用 End_Search 来清理 A_Search 对象。这基本上重置了它,因此它不再包含任何条目。

如果我们使用被动迭代器,我们可以避免必须管理这种基本的日常维护工作。使用被动迭代器时,程序如下所示

with Ada.Text_IO;
with Ada.Directories; use Ada.Directories;
with Ada.Calendar.Formatting;

procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
   package IOI is new IO.Integer_IO (D.File_Size);
   package ACF renames Ada.Calendar.Formatting;
   
   procedure Write_Search_Item (Search_Item : in D.Directory_Entry_Type) is
   begin
      IO.Put (Item => D.Simple_Name (Directory_Entry => Search_Item));
      IO.Set_Col (To => 25);
      if D.Kind (Directory_Entry => Search_Item) = D.Ordinary_File then
         IOI.Put (Item  => D.Size (Directory_Entry => Search_Item),
                  Width => 1);
         IO.Put (Item => " bytes");
      else
         IO.Put (Item => "dir");
      end if;
      IO.Set_Col (To => 45);
      IO.Put (Item => ACF.Image
              (D.Modification_Time (Directory_Entry => Search_Item)));
      IO.Set_Col (To => 70);
      IO.Put (Item => D.Full_Name (Directory_Entry => Search_Item));
      IO.New_Line; 
   end Write_Search_Item;

   Filter : constant D.Filter_Type := (D.Ordinary_File => True,
                                       D.Special_File => False,
                                       D.Directory => True);
begin
   D.Search (Directory => D.Current_Directory, 
             Pattern => "", 
             Filter => Filter, 
             Process => Write_Search_Item'Access);
end aDir;

输出为

 /home/thomas/wiki_examples/aDir/adir
 .                       dir                 2009-10-23 20:17:22      /home/thomas/wiki_examples/aDir/.
 ..                      dir                 2009-09-24 20:07:57      /home/thomas/wiki_examples/aDir/..
 objects                 dir                 2009-10-27 20:56:32      /home/thomas/wiki_examples/aDir/objects
 Proj.gpr                502 bytes           2009-09-24 20:09:20      /home/thomas/wiki_examples/aDir/Proj.gpr
 adir                    594193 bytes        2009-10-23 20:17:22      /home/thomas/wiki_examples/aDir/adir
 some_dir                dir                 2009-10-06 14:10:25      /home/thomas/wiki_examples/aDir/some_dir
 adir.adb                1781 bytes          2009-10-23 20:17:21      /home/thomas/wiki_examples/aDir/adir.adb
 some_file               7 bytes             2009-10-06 14:10:04      /home/thomas/wiki_examples/aDir/some_file
 some_new_file           7 bytes             2009-10-06 14:37:15      /home/thomas/wiki_examples/aDir/some_new_file

使用被动迭代器,您将摆脱 Search_TypeStart_Search -> More_Entries -> Get_Next_Entry -> End_Search 链。它更加干净,也更容易避免错误,因为您不必担心忘记最后的 End_Search 调用。不过,两种方法都有各自的优势,因此请根据具体情况选择最合适的方案。

Search 过程接受的参数与 Start_Search 几乎相同,除了我们使用 Process 而不是 SearchProcess 当然是访问要处理搜索返回的每个条目的子程序。这个子程序必须接受一个参数:Item : in Directory_Entry_Type

{{collapsible box|title=Ada.Directories.Start_Search 示例源代码|collapsed=yes|content=

with Ada.Text_IO;
with Ada.Directories; use Ada.Directories;
with Ada.Calendar.Formatting;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
   package IOI is new IO.Integer_IO (D.File_Size);
   package ACF renames Ada.Calendar.Formatting;
 
   A_Search : D.Search_Type;
   Search_Item : D.Directory_Entry_Type;
   Filter : constant D.Filter_Type := (D.Ordinary_File => True,
                                       D.Special_File => False,
                                       D.Directory => True);
begin
   D.Start_Search (Search    => A_Search,
                   Directory => D.Current_Directory,
                   Pattern   => "",
                   Filter    => Filter);
   while D.More_Entries (Search => A_Search) loop
      D.Get_Next_Entry (Search          => A_Search,
                        Directory_Entry => Search_Item);
      IO.Put (Item => D.Simple_Name (Directory_Entry => Search_Item));
      IO.Set_Col (To => 25);
      if D.Kind (Directory_Entry => Search_Item) = D.Ordinary_File then
         IOI.Put (Item  => D.Size (Directory_Entry => Search_Item),
                  Width => 1);
         IO.Put (Item => " bytes");
      else
         IO.Put (Item => "dir");
      end if;
      IO.Set_Col (To => 45);
      IO.Put (Item => ACF.Image
              (D.Modification_Time (Directory_Entry => Search_Item)));
      IO.Set_Col (To => 70);
      IO.Put (Item => D.Full_Name (Directory_Entry => Search_Item));
      IO.New_Line;
   end loop;
   D.End_Search (Search => A_Search);
end Adir;
with Ada.Text_IO;
with Ada.Directories; use Ada.Directories;
with Ada.Calendar.Formatting;
 
procedure aDir is
   package IO renames Ada.Text_IO;
   package D renames Ada.Directories;
   package IOI is new IO.Integer_IO (D.File_Size);
   package ACF renames Ada.Calendar.Formatting;
 
   procedure Write_Search_Item (Search_Item : in D.Directory_Entry_Type) is
   begin
      IO.Put (Item => D.Simple_Name (Directory_Entry => Search_Item));
      IO.Set_Col (To => 25);
      if D.Kind (Directory_Entry => Search_Item) = D.Ordinary_File then
         IOI.Put (Item  => D.Size (Directory_Entry => Search_Item),
                  Width => 1);
         IO.Put (Item => " bytes");
      else
         IO.Put (Item => "dir");
      end if;
      IO.Set_Col (To => 45);
      IO.Put (Item => ACF.Image
              (D.Modification_Time (Directory_Entry => Search_Item)));
      IO.Set_Col (To => 70);
      IO.Put (Item => D.Full_Name (Directory_Entry => Search_Item));
      IO.New_Line; 
   end Write_Search_Item;
 
   Filter : constant D.Filter_Type := (D.Ordinary_File => True,
                                       D.Special_File => False,
                                       D.Directory => True);
begin
   D.Search (Directory => D.Current_Directory, 
             Pattern => "", 
             Filter => Filter, 
             Process => Write_Search_Item'Access);
end aDir;


[编辑 | 编辑源代码]

End_Search 的规范如下所示

procedure End_Search (Search : in out Search_Type);

End_Search 是一个清理过程。只有在您之前调用过 Start_Search 时才需要使用 End_Search。它用于重置 Search_Type,有效地清除所有搜索条目。

典型的用法如下所示

Start_Search(Search => A_Search, ...);
while More_Entries (Search => A_Search) loop
   Get_Next_Entry (Search => A_Search, ...);
   --  Do stuff
end loop;
End_Search (Search => A_Search);

实际的使用示例可以在 此处 找到。

More_Entries

[编辑 | 编辑源代码]

More_Entries 的规范如下所示

function More_Entries (Search : Search_Type) return Boolean;

More_Entries 仅在之前调用过 Start_Search 时才相关。调用 More_Entries 会返回布尔值 True,如果在调用 Get_Next_Entry 时还有更多条目可用。否则将返回布尔值 False。有关实际的使用示例,请参见 Start_Search

Get_Next_Entry

[编辑 | 编辑源代码]

Get_Next_Entry 的规范如下所示

procedure Get_Next_Entry
  (Search          : in out Search_Type;
   Directory_Entry : out Directory_Entry_Type);

我将直接引用 Ada 参考手册 中关于 Get_Next_Entry 的内容

返回与模式和过滤器匹配的 Search 描述的搜索的下一个 Directory_Entry。如果不再有匹配项,则会引发 Status_Error。实现定义了如果 Directory 的内容在 Search 对象有效时发生更改(例如,由另一个程序),此例程返回的结果是否会发生更改。如果外部环境不支持对 Search 代表的目录的持续搜索,则会传播 Use_Error 异常。

这在 Start_Search 部分中有说明。

Simple_Name (目录条目)

[编辑 | 编辑源代码]

`Simple_Name` 的规范如下所示

function Simple_Name (Directory_Entry : Directory_Entry_Type) return String;

Simple_Name 函数的功能与“常规” Simple_Name 函数完全相同,只是它接受 Directory_Entry_Type 而不是 String 作为 Directory_Entry 参数。有关示例,请参见 Start_Search

Full_Name (目录条目)

[编辑 | 编辑源代码]

`Full_Name` 的规范如下所示

function Full_Name (Directory_Entry : Directory_Entry_Type) return String;

Full_Name 函数的功能与“常规” Full_Name 函数完全相同,只是它接受 Directory_Entry_Type 而不是 String 作为 Directory_Entry 参数。有关示例,请参见 Start_Search

Kind (目录条目)

[编辑 | 编辑源代码]

Kind 的规范如下所示

function Kind (Directory_Entry : Directory_Entry_Type) return File_Kind;

Kind 函数的功能与“常规” Kind 函数完全相同,只是它接受 Directory_Entry_Type 而不是 String 作为 Directory_Entry 参数。有关示例,请参见 Start_Search

Size (目录条目)

[编辑 | 编辑源代码]

Size 的规范如下所示

function Size (Directory_Entry : Directory_Entry_Type) return File_Size;

Size 函数的功能与“常规” Size 函数完全相同,只是它接受 Directory_Entry_Type 而不是 String 作为 Directory_Entry 参数。有关示例,请参见 Start_Search

Modification_Time (目录条目)

[编辑 | 编辑源代码]

Modification_Time 的规范如下所示

function Modification_Time
     (Directory_Entry : Directory_Entry_Type) return Ada.Calendar.Time;

Modification_Time 函数的功能与“常规” Modification_Time 函数完全相同,只是它接受 Directory_Entry_Type 而不是 String 作为 Directory_Entry 参数。有关示例,请参见 Start_Search

--                     Standard Ada library specification
--   Copyright (c) 2003-2018 Maxim Reznik <[email protected]>
--   Copyright (c) 2004-2016 AXE Consultants
--   Copyright (c) 2004, 2005, 2006 Ada-Europe
--   Copyright (c) 2000 The MITRE Corporation, Inc.
--   Copyright (c) 1992, 1993, 1994, 1995 Intermetrics, Inc.
--   SPDX-License-Identifier: BSD-3-Clause and LicenseRef-AdaReferenceManual
-- -------------------------------------------------------------------------

with Ada.Calendar;
with Ada.IO_Exceptions;

package Ada.Directories is

   --   Directory and file operations:

   function Current_Directory return String;

   procedure Set_Directory (Directory : in String);

   procedure Create_Directory (New_Directory : in String;
                               Form          : in String := "");

   procedure Delete_Directory (Directory : in String);

   procedure Create_Path (New_Directory : in String;
                          Form          : in String := "");

   procedure Delete_Tree (Directory : in String);

   procedure Delete_File (Name : in String);

   procedure Rename (Old_Name : in String;
                     New_Name : in String);

   procedure Copy_File (Source_Name : in String;
                        Target_Name : in String;
                        Form        : in String := "");

   --   File and directory name operations:

   function Full_Name (Name : in String) return String;

   function Simple_Name (Name : in String) return String;

   function Containing_Directory (Name : in String) return String;

   function Extension (Name : in String) return String;

   function Base_Name (Name : in String) return String;

   function Compose (Containing_Directory : in String := "";
                     Name                 : in String;
                     Extension            : in String := "")
     return String;

   --   File and directory queries:

   type File_Kind is (Directory, Ordinary_File, Special_File);

   type File_Size is range 0 .. implementation_defined;

   function Exists (Name : in String) return Boolean;

   function Kind (Name : in String) return File_Kind;

   function Size (Name : in String) return File_Size;

   function Modification_Time (Name : in String) return Ada.Calendar.Time;

   --   Directory searching:

   type Directory_Entry_Type is limited private;

   type Filter_Type is array (File_Kind) of Boolean;

   type Search_Type is limited private;

   procedure Start_Search
    (Search     : in out Search_Type;
     Directory  : in     String;
     Pattern    : in     String;
     Filter     : in     Filter_Type := (others => True));

   procedure End_Search (Search : in out Search_Type);

   function More_Entries (Search : in Search_Type) return Boolean;

   procedure Get_Next_Entry (Search          : in out Search_Type;
                             Directory_Entry :    out Directory_Entry_Type);

   procedure Search
    (Directory : in String;
     Pattern   : in String;
     Filter    : in Filter_Type := (others => True);
     Process   : not null access procedure
                  (Directory_Entry : in Directory_Entry_Type));

   --   Operations on Directory Entries:

   function Simple_Name (Directory_Entry : in Directory_Entry_Type)
     return String;

   function Full_Name (Directory_Entry : in Directory_Entry_Type)
     return String;

   function Kind (Directory_Entry : in Directory_Entry_Type)
     return File_Kind;

   function Size (Directory_Entry : in Directory_Entry_Type)
     return File_Size;

   function Modification_Time (Directory_Entry : in Directory_Entry_Type)
     return Ada.Calendar.Time;

   Status_Error : exception renames Ada.IO_Exceptions.Status_Error;
   Name_Error   : exception renames Ada.IO_Exceptions.Name_Error;
   Use_Error    : exception renames Ada.IO_Exceptions.Use_Error;
   Device_Error : exception renames Ada.IO_Exceptions.Device_Error;

private

   pragma Import (Ada, Directory_Entry_Type);
   pragma Import (Ada, Search_Type);

end Ada.Directories;

另请参见

[编辑 | 编辑源代码]

维基教科书

[编辑 | 编辑源代码]

外部示例

[编辑源代码]

Ada 参考手册

[编辑 | 编辑源代码]

开源实现

[编辑 | 编辑源代码]

FSF GNAT

drake

华夏公益教科书