開始使用
在BOOST庫出現之前,C++對於文件和目錄的操作,大都借助於UNIX提供的底層文件和目錄接口,從使用角度來看,這些底層的操作不夠友好。BOOST中filesystem庫是一種可移植的文件系統操作庫,可以跨平台的操作目錄、文件等,在不失性能的情況下,提供了友好的操作方法。
本文主要介紹在UNIX環境中,boost::filesystem的常用操作方法。
假設你已經安裝好了boost庫,使用boost::filesystem需要加上頭文件
#include <boost/filesystem.hpp>
編譯時,需要鏈接
-lboost_filesystem
當安裝路徑不是UNIX環境變量中設置的標准路徑的話,編譯時還需加上boost庫頭文件和動態路路徑,即:
-I $(BOOST)/include/ -L $(BOOST)/lib/
變量$(BOOST)是BOOST庫實際安裝路徑。
filesystem介紹
filesystem庫是一個可移植的文件系統操作庫,它在底層做了大量的工作,使用POSIX標准表示文件系統的路徑,使C++具有了類似腳本語言的功能,可以跨平台操作目錄、文件,寫出通用的腳本程序。
1.path的構造函數可以接受C字符串和string,也可以是一個指定首末迭代器字符串序列區間。
2.filesystem提供了一系列的文件名(或目錄)檢查函數。
3.有豐富的函數用於獲取文件名、目錄名、判斷文件屬性等等。
4.filesystem庫使用異常來處理文件操作時發生的錯誤。
5.filesystem庫提供一個文件狀態類file_status及一組相關函數,用於檢查文件的各種屬性,如是否存在、是否是目錄、是否是符號鏈接等。
6.filesystem提供了少量的文件屬性操作,如windows下的只讀、歸檔等,Linux下的讀寫權限等。
7.文件操作,如創建目錄、文件改名、文件刪除、文件拷貝等等。
8.basic_directory_iterator提供了迭代一個目錄下所有文件的功能。
path類的基本用法
//注意 /= 和 += 的區別, /= 表示追加下級目錄, += 僅僅是字符串的串接 path dir("C:\\Windows"); dir /= "System32"; //追加下級目錄 dir /= "services.exe"; std::cout << dir << std::endl; std::cout << dir.string() << std::endl; //轉換成std::string 類型 std::cout << dir.root_name()<< std::endl; //盤符名:C: std::cout << dir.root_directory()<< std::endl; //根目錄:"\" std::cout << dir.root_path()<< std::endl; //根路徑:"C:\" std::cout << dir.relative_path()<< std::endl; // 相對路徑:Windows\System32\services.exe std::cout << dir.parent_path()<< std::endl; //上級目錄:C:\Windows\System32 std::cout << dir.filename()<< std::endl; //文件名:services.exe std::cout << dir.stem()<< std::endl; //不帶擴展的文件名:services std::cout << dir.extension()<< std::endl; //擴展名:.exe
常用函數及異常處理
system_complete(path);// 返回完整路徑(相對路徑+當前路徑) exists(path);// 目錄是否存在 is_directory(path);// is_directory(file_status);// 是否是路徑 is_regular_file(path);// is_regular_file(file_status);// 是否是普通文件 is_symlink(path);// is_symlink(file_status);// 是否是一個鏈接文件 file_status status(path);// 返回路徑名對應的狀態 initial_path();// 得到程序運行時的系統當前路徑 current_path();// 得到系統當前路徑 current_path(const Path& p);// 改變當前路徑 space_info space(const Path& p);// 得到指定路徑下的空間信息,space_info 有capacity, free 和 available三個成員變量,分別表示容量,剩余空間和可用空間。 last_write_time(const Path& p);// 最后修改時間 last_write_time(const Path& p, const std::time_t new_time);// 修改最后修改時間 bool create_directory(const Path& dp);// 建立路徑 create_hard_link(const Path1& to_p, const Path2& from_p);// error_code create_hard_link(const Path1& to_p, const Path2& from_p, error_code& ec);// 建立硬鏈接 create_symlink(const Path1& to_p, const Path2& from_p);// create_symlink(const Path1& to_p, const Path2& from_p, error_code& ec);// 建立軟鏈接 remove(const Path& p, system::error_code & ec = singular );// 刪除文件 remove_all(const Path& p);// 遞歸刪除p中所有內容,返回刪除文件的數量 rename(const Path1& from_p, const Path2& to_p);// 重命名 copy_file(const Path1& from_fp, const Path2& to_fp);// 拷貝文件 omplete(const Path& p, const Path& base=initial_path<Path>());// 以base以基,p作為相對路徑,返回其完整路徑 create_directories(const Path & p);// 建立路徑
實例
路徑(path類)和迭代器–filesystem操作的基礎
path類提供了路徑操作的豐富接口,可以獲得文件名、拓展名、文件屬性等。迭代器提供了遍歷整個目錄所有文件的功能,常用的filesystem庫的迭代器是:directory_iterator和recursive_directory_iterator,后者相對於前者提供了遞歸遍歷的功能。
基於路徑和迭代器,下文已迭代目錄(cur/)為例,簡介filesystem的基本操作:
首先,定義要處理文件的路徑
string curPath = “/home/test/cur/” ;
條件假設:
1).cur目錄下結構如下
cur/
—build.sh
—src/
——main.cpp
——makefile
2).進入/home/test/cur目錄,執行build.sh編譯程序后,留在當前目錄執行可執行文件
3).假設程序掃描目錄時,首先掃描到的文件時 build.sh
//定義一個可以遞歸的目錄迭代器,用於遍歷 boost::filesystem::recursive_directory_iterator itEnd; for(boost::filesystem::recursive_directory_iterator itor( curPath.c_str() ); itor != itEnd ;++itor) { //itor->path().string()是目錄下文件的路徑 /* *當curPath是相對路徑時,itor->string()也是相對路徑 *即當curPath = "../cur/",下面將輸出"../cur/build.sh" */ //當curPath是絕對路徑時,itor->string()也是絕對路徑 string file = itor->path().string() ; // "/home/test/cur/build.sh" //構造文件路徑,以獲得文件豐富的操作 //path可以接受C風格字符串和string類型作為構造函數的參數,而提供的路徑可以是相對路徑,也可以是絕對路徑。 boost::filesystem::path filePath(file); //path的方法如filename()等,返回的對象仍是path,如果可以通過path的string()方法,獲取對象的string類型 //parent_path()獲得的是當前文件的父路徑 cout<<filePath.parent_path()<<endl; // "/home/test/cur/" //filename()獲得的是文件名,含拓展名 cout<<filePath.filename()<<endl; // "build.sh" cout<<filePath.filename().string()<<endl; //stem()獲得的是文件的凈文件名,即不含拓展名 cout<<filePath.stem()<<endl; // "build" //extension()文件的拓展名(主要是".sh"而不是"sh") cout<<filePath.extension()<<endl; // ".sh" //獲得文件的大小,單位為字節 int nFileSize = boost::filesystem::file_size(filePath); //最后一次修改文件的時間 //last_write_time()返回的是最后一次文件修改的絕對秒數 //last_write_time(filePath,time(NULL))還可以修改文件的最后修改時間,相當於Linux中命令的touch if(filePath.last_write_time() - time(NULL) > 5) { /* *在工程實踐中,當需要不斷的掃目錄,而目錄又會不斷的加入新文件時, *借助last_write_time()可以判斷新入文件的完整性,以避免錯誤的處理還未寫完的文件 */ } //判斷文件的狀態信息 if(boost::filesystem::is_regular_file(file)) { //is_regular_file(file)普通文件 //is_directory(file)目錄文件,如當遍歷到"/home/test/cur/src/"時,這就是一個目錄文件 //is_symlink(file)鏈接文件 ... } //更改拓展名 boost::filesystem::path tmpPath = filePath; //假設遍歷到了cpp文件,想看下對應的.o文件是否存在 tmpPath.replace_extension(".o"); //判斷文件是否存在 if( boost::filesystem::exists( tmpPath.string() ) ) //刪除文件 //remove只能刪除普通文件,而不能刪除目錄 boost::filesystem::remove(tmpPath.string()); //remove_all則提供了遞歸刪除的功能,可以刪除目錄 boost::filesystem::remove_all(tmpPath.string()); //移動文件 & 拷貝文件 //srcPath原路徑,srcPath的類型為string //destPath目標路徑,destPath的類型為string boost::filesystem::rename(srcPath , destPath); boost::filesystem::copy_file(srcPath , destPath); //拷貝目錄 boost::filesystem::copy_files("/home/test","/dev/shm") } boost::filesystem還可以創建目錄: if( !boost::filesystem::exists( strFilePath ) ) { boost::filesystem::create_directories(strFilePath) }
boost::filesystem提供的操作當然不只如此,詳見參考文件1。使用boost::filesystem操作時加上異常捕獲,也能夠增加代碼的魯棒性,在此不進行累述。