跳轉到內容

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 <reznikmm@gmail.com>
--   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

華夏公益教科書