天天看點

BOOST 之filesystem, path

目錄[-]

<code>c++</code> 語言(實際上是 <code>c++</code> 标準)的最常見問題之一是,缺乏定義良好的庫來幫助處理檔案系統查詢和操作。由于這個原因,程式員不得不使用本機作業系統提供的應用程式程式設計接口(application

program interfaces,api),而這使得代碼不能在平台之間移植。以下面的簡單情況為例:您需要确定某個檔案是否是 directory 類型。在

microsoft? windows? 平台中,可以通過調用 <code>getattributes</code> 庫函數(在

windows.h 頭檔案中定義)進行此操作:

對于目錄,所得到的結果應該為 file_attribute_directory,而您的代碼必須檢查是否為此結果。在 unix? 和 linux?

平台上,可以通過使用 <code>stat</code> 或 <code>fstat</code> 函數及

sys/stat.h 中定義的 s_isdir

宏來實作相同的功能。您還必須了解 <code>stat</code> 結構。下面是對應的代碼:

對于 i/o 操作較多的程式,這樣的不一緻就意味着需要進行大量的工程工作才能在平台間移植代碼。正是因為這個原因,我們才引入了 boost

filesystem

library。這個廣泛使用的庫提供了安全、可移植且易用的 <code>c++</code> 接口,用于執行檔案系統操作。可以從  站點免費下載下傳此庫。

在深入研究 boost filesystem library 的更多細節之前,請看一下 中所示的代碼;此代碼使用 boost api 确定某個檔案的類型是否為 directory。

此代碼非常明了易懂,您并不需要了解任何系統特定的例程。此代碼經過驗證,能在不用修改的情況下在 gcc-3.4.4 和 cl-13.10.3077

上成功編譯。

了解 boost filesystem library 的關鍵是 <code>path</code> 對象,因為 filesystem

library

中定義的多個例程都要對相應的 <code>path</code> 對象操作。檔案系統路徑通常依賴于作業系統。例如,衆所周知,unix 和

linux 系統使用正斜杠 (<code> /</code>) 字元作為目錄分隔符,而 windows 将反斜杠 (<code>\</code>)

字元用于類似的用途。<code>boost::filesystem::path</code> 旨在準确地抽象此特性。<code>path</code> 對象可以通過多種方式進行初始化,最常見的方式是使用 <code>char*</code> 或<code>std::string</code> 進行初始化,如 中所示。

在初始化 <code>path</code> 對象時,可以采用本機格式或可移植作業系統接口(portable operating

system interface,posix)委員會定義的可移植格式提供 pathname

變量。這兩種方法在實際中各有優缺點。考慮以下情況:您希望操作軟體所建立的目錄,此目錄在 unix 和 linux 系統上位于 /tmp/mywork,而在

windows 上位于 c:\tmp\mywork。可以采用多種方法處理問題。 顯示了面向本機格式的方法。

需要單個 <code>#ifdef</code> 來按作業系統初始化 path 對象。不過,如果您喜歡使用可移植格式,請參見。

請注意,<code>path::name_check</code> 指的是一個名稱檢查函數原型。如果其參數輸入 pathname

對于特定的作業系統或檔案系統有效,名稱檢查函數将傳回“true”。boost filesystem library

提供了多個名稱檢查函數,而且也歡迎您提供自己的變體。常用的名稱檢查函數是 boost

提供的<code>portable_posix_name</code> 和 <code>windows_name</code>。

<code>path</code> 對象提供了多個成員方法。這些成員例程并不會修改檔案系統,但會根據 path

名稱提供有用的資訊。此部分提供了其中幾個例程的概述:

<code>const std::string&amp; string( )</code>:此例程會傳回用于初始化

path 的字元串的副本,其格式符合 path 文法規則。

<code>std::string root_directory( )</code>:在提供了路徑的情況下,此

api 将傳回根目錄,否則将傳回空字元串。例如,如果路徑包含/tmp/var1,則此例程将傳回 <code>/</code>,即

unix 檔案系統的根。不過,如果路徑是相對路徑,如 ../mywork/bin,此例程将傳回空字元串。

<code>std::string root_name( )</code>:在給定從檔案系統根目錄開始的路徑的情況下,此例程将傳回包含 pathname 的第一個字元的字元串。

<code>std::string leaf( )</code>:在給定絕對路徑名稱(例如,/home/user1/file2)的情況下,此例程将提供與檔案名稱對應的字元串(即

file2)。

<code>std::string branch_path( )</code>:這是與 <code>leaf</code> 互補的例程。在給定路徑的情況下,将會傳回其構造所用的所有元素(除了最後一個元素)。例如,對于使用 /a/b/c 初始化的

path,<code>path.branch_path( )</code> 将傳回 <code>/a/b</code>。對于包含單個元素的路徑,如 c,此例程将傳回空字元串。

<code>bool empty( )</code>:如果 path

對象包含空字元串(例如 path path1("")),則此例程将傳回 true。

<code>boost::filesystem::path::iterator</code>:此例程用于周遊

path 的各個元素。請看 所示的代碼。

上述程式的輸出依次是 <code>/</code>、<code>usr</code>、<code>local</code>、<code>include</code>,代表了該目錄的層次結構。

<code>path operator / (char* lhs, const path&amp; rhs)</code>:此例程是 <code>path</code> 的非成員函數。它将傳回使用 <code>lhs</code> 和 <code>rhs</code> 形成的路徑的串聯值。它将自動插入 <code>/</code> 作為路徑分隔符,如 中所示。

檔案系統操作經常遇到意外的問題,boost filesystem library

将使用 <code>c++</code> 異常報告運作時錯誤。<code>boost::filesystem_error</code> 類派生自<code>std::runtime_error</code> 類。庫中的函數使用 <code>filesystem_error</code> 異常報告操作錯誤。與不同的可能錯誤類型對應,boost

頭檔案定義了相應的錯誤代碼。使用者代碼通常駐留在 <code>try...catch</code> 塊内,使用 <code>filesystem_error</code> 異常來報告相關錯誤消息。 提供了重命名檔案的小示例,在 <code>from</code> 路徑中的檔案不存在時引發異常。

<code>boost::filesystem</code> 提供了不同類别的函數:有些函數(如 <code>is_directory</code>)用于查詢檔案系統,而其他函數(如 <code>create_directory</code>)則主動對檔案系統進行修改。根據各自功能的不同,這些函數可以大略歸入以下類别:

屬性函數:提供雜項資訊,如檔案大小、磁盤使用量等。

檔案系統操作函數:用于建立正常檔案、目錄和符号連結;複制和重命名檔案;提供删除功能。

實用工具:測試檔案的擴充名等。

雜項正常函數:以程式設計方式更改檔案擴充名等。

boost filesystem library 包括以下屬性函數:

<code>uintmax_t file_size(const path&amp;)</code>:傳回正常檔案的大小(以位元組為機關)

<code>boost::filesystem::space_info space(const path&amp;)</code>:接受路徑作為輸入,并傳回定義如下的 <code>space_info</code> 結構:

根據檔案系統所屬的磁盤分區,此流程将對該分區的所有目錄傳回相同的磁盤使用量統計資料(以位元組為機關)。例如,對于 c:\src\dir1 和

c:\src\dir2,都會傳回相同的磁盤使用資料。

<code>std::time_t last_write_time(const path&amp;)</code>:傳回檔案的最後修改時間。

<code>void last_write_time(const path&amp;, std::time_t new_time)</code>:修改檔案的最後修改時間。

<code>const path&amp; current_path( )</code>:傳回程式的目前工作目錄的完整路徑(注意,此路徑與最初運作程式的路徑可能不同,因為可能采用程式設計方式更改目錄)。

這組函數負責進行新檔案和目錄建立、檔案删除等操作:

<code>bool create_directory(const path&amp;)</code>:此函數使用給定的路徑名稱建立目錄。(請注意,如果 pathname

本身包含無效字元,則結果經常是由平台定義的。例如,在 unix 和 windows 系統中,星号 (<code>*</code>)、問号

(<code>?</code>) 及其他此類字元視為無效,不能出現在目錄名稱中。)

<code>bool create_directories(const path&amp;)</code>:與建立單個目錄相對,您可以使用此 api 建立目錄樹。例如,以目錄樹 /a/b/c 為例,必須在

/tmp 檔案夾内建立此目錄樹。可調用此 api

完成任務,但使用相同的參數調用 <code>create_directory</code> 時将引發異常。

<code>bool create_hard_link (const path&amp; frompath, const path&amp; topath)</code>:此函數在 <code>frompath</code> 和 <code>topath</code> 間建立硬連結。

<code>bool create_symlink(const path&amp; frompath, const path&amp; topath)</code>:此函數在 <code>frompath</code> 和 <code>topath</code> 間建立符号(軟)連結。

<code>void copy_file(const path&amp; frompath, const path&amp; topath)</code>:将 <code>frompath</code> 引用的檔案的内容和屬性複制到 <code>topath</code> 引用的檔案中。例程expects

a destination file to be absent;如果存在目标檔案,則會引發異常。是以,此函數與 unix

中系統指定的 <code>cp</code> 指令并不等效。另外,此函數還預期 <code>frompath</code> 變量将引用正确的正常檔案。請看以下示例:<code>frompath</code> 引用符号連結

/tmp/file1,而後者反過來引用檔案 /tmp/file2;而 <code>topath</code> 可以為

/tmp/file3。在這種情況下,<code>copy_file</code> 将失敗。這是此 api

與 <code>cp</code> 指令相比的另一個差别。

<code>void rename(const path&amp; frompath, const path&amp; topath)</code>:此函數是用于重命名檔案的

api。可以通過在 <code>topath</code> 參數中指定完整路徑名來同時重命名和更改檔案的位置,如 中所示。

<code>bool remove(const path&amp; p)</code>:此例程将嘗試删除路徑 p 所引用的檔案或目錄。對于目錄的情況,如果目錄的内容不為空,則此例程将引發異常。警告:此例程并不考慮所删除的内容,即使其他程式在通路同一檔案也如此!

<code>unsigned long remove_all(const path&amp; p)</code>:此

api

嘗試删除路徑 p 所引用的檔案或目錄。與 <code>remove</code> 不同,此函數并不會特殊考慮不為空的目錄。此函數是

unix <code>rm –rf</code> 指令的 boost 對等項。

boost filesystem library 包含以下實用工具:

<code>bool exists(const path&amp;)</code>:此函數檢查檔案的擴充名。檔案可以為任何類型:正常檔案、目錄、符号連結等等。

<code>bool is_directory(const path&amp;)</code>:此函數檢查路徑是否與目錄對應。

<code>bool is_regular(const path&amp;)</code>:此函數檢查普通檔案(即此檔案不是目錄、符号連結、套接字或裝置檔案)。

<code>bool is_other(const path&amp;)</code>:通常,此函數檢查裝置檔案(如

/dev/tty0)或套接字檔案。

<code>bool is_empty(const path&amp;)</code>:如果路徑與檔案夾對應,此函數将檢查檔案夾是否為空,并據此傳回“true”或“false”。如果路徑與檔案對應,此函數将檢查檔案的大小是否等于

0。對于檔案的硬連結或符号連結的情況,此 api 将檢查原始檔案是否為空。

<code>bool equivalent(const path1&amp; p1, const path2&amp; p2)</code>:此 api 非常實用,可用于比較相對路徑和絕對路徑名。請看:

<code>path system_complete(const path&amp;)</code>:此函數是與 <code>bool equivalent(const path1&amp; p1, const path2&amp; p2)</code> 同一系列的另一個 api。在給定目前工作目錄中任意檔案路徑的情況下,此 api

将傳回該檔案的絕對路徑。例如,如果使用者位于目錄 /home/user1 并查詢檔案

../user2/file2,此函數将傳回 <code>/home/user2/file2</code>,即檔案 file2

的完整路徑名。

boost filesystem library 包括以下雜項函數:

<code>std::string extension(const path&amp;)</code>:此函數以前面帶句點 (<code>.</code>)

的形式傳回給定檔案名的擴充名。例如,對于檔案名為 test.cpp 的檔案,<code>extension</code> 将傳回 <code>.cpp</code>。對于檔案沒有擴充名的情況,此函數将傳回空字元串。對于隐藏檔案(即

unix

系統中檔案名以 <code>.</code> 開始的檔案),此函數将相應地計算擴充名類型或傳回空字元串(是以,對于 .test.profile,此例程将傳回 <code>.profile</code>)。

<code>std::string basename(const path&amp;)</code>:這是與 <code>extension</code> 互補的例程。它将傳回檔案名中 <code>.</code> 之前的字元串。請注意,即使提供了絕對檔案名,此

api 仍然僅會傳回屬于檔案名的直接部分,如 中所示。

<code>std::string change_extension(const path&amp; oldpath, const std::string new_extension)</code>:此 api

将傳回反映更改後的名稱的新字元串。請注意,與 <code>oldpath</code> 對應的檔案保持不變。這隻是一個正常函數。另請注意,您必須顯式地在擴充名中指定點。例如,<code>change_extension("test.c", "so")</code> 會得到 <code>testso</code>,而不是 <code>test.so</code>。

本文提供了 boost filesystem library 的簡單概述。不應将本文視為 boost 中的整個檔案系統接口的綜合文檔。并未讨論此 api

集的内部情況,也沒有讨論這些 api 在非 unix 或 windows 平台(如 vms)中的細節。有關檔案系統的更多資訊,請參見。