boost::filesystem::resize_file函數的源碼分析

通過分析一個非常簡單的函數:resize_file,來初步瞭解boost的源代碼佈局。
filesystem庫是需要編譯成庫才能使用的。要使用filesystem庫,首先需要包含頭文件boost/filesystem.hpp,然後需要鏈接庫文件,windows下的 vs2010比較智能,能夠自動鏈接,linux則需要指定鏈接庫文件libboost_filesystem.a,在這裏vs2010用到的庫文件是boost_filesystem-vc100-mt-1_44.lib。

boost/filesystem.hpp是一個純粹引用其他頭文件的頭文件。代碼如下:

#ifndef BOOST_FILESYSTEM_FILESYSTEM_HPP
#define BOOST_FILESYSTEM_FILESYSTEM_HPP

# if defined(BOOST_FILESYSTEM_VERSION) \
  && BOOST_FILESYSTEM_VERSION != 2  && BOOST_FILESYSTEM_VERSION != 3
#   error BOOST_FILESYSTEM_VERSION defined, but not as 2 or 3
# endif

# if !defined(BOOST_FILESYSTEM_VERSION)
#   define BOOST_FILESYSTEM_VERSION 2
# endif

#if BOOST_FILESYSTEM_VERSION == 2
#  include <boost/filesystem/v2/config.hpp>
#  include <boost/filesystem/v2/path.hpp>
#  include <boost/filesystem/v2/operations.hpp>
#  include <boost/filesystem/v2/convenience.hpp>

# else
#  include <boost/filesystem/v3/config.hpp>
#  include <boost/filesystem/v3/path.hpp>
#  include <boost/filesystem/v3/operations.hpp>
#  include <boost/filesystem/v3/convenience.hpp>

# endif

#endif  // BOOST_FILESYSTEM_FILESYSTEM_HPP 

在這裏可以看到boost 1_44_0的filesystem庫包含了兩個版本,V2和V3,其中只有V3版本纔有resize_file接口,所以要使用resize_file必須先在自己的工程中定義宏:
#define BOOST_FILESYSTEM_VERSION 
boost\filesystem\v3\operations.hpp 中:
inline  // name suggested by Scott McMurray
  void resize_file(const path& p, uintmax_t size) {detail::resize_file(p, size);}

  inline
  void resize_file(const path& p, uintmax_t size, system::error_code& ec)
                                       {detail::resize_file(p, size, &ec);}

然後再看detail命名空間的resize_file,它的實現則在libs\filesystem\v3\src\operations.cpp
進入到這個文件中看到如下代碼:
BOOST_FILESYSTEM_DECL
  void resize_file(const path& p, uintmax_t size, system::error_code* ec)
  {
    error(!BOOST_RESIZE_FILE(p.c_str(), size), p, ec, "boost::filesystem::resize_file");
  }
這裏定義了一個BOOST_RESIZE_FILE的宏,再看operations.cpp中代碼片段:
# if defined(BOOST_POSIX_API)
...
#   define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0)
...
# else  // BOOST_WINDOWS_API
...
#   define BOOST_RESIZE_FILE(P,SZ)(resize_file_api(P, SZ)!= 0)
...
# endif

這裏根據宏BOOST_POSIX_API來區分支持posix api的操作系統和windows操作系統。
注:POSIX 表示可移植操作系統接口(Portable Operating System Interface) ,一般類unix內核的操作系統都支持,例如unix,linux,freebsd,mac。
其中類unix平臺的實現比較簡單,直接調用truncate函數。windows下稍微複雜,調用了自定義的resize_file_api函數,再進一步分析代碼:

  BOOL resize_file_api(const wchar_t* p, boost::uintmax_t size)
  {
    HANDLE handle = CreateFileW(p, GENERIC_WRITE, 0, 0, OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL, 0);
    LARGE_INTEGER sz;
    sz.QuadPart = size;
    return handle != INVALID_HANDLE_VALUE
      && ::SetFilePointerEx(handle, sz, 0, FILE_BEGIN)
      && ::SetEndOfFile(handle)
      && ::CloseHandle(handle);
  }

終於看到windows下的resize_file的廬山真面目了,這裏調用了4個windows api函數才實現了函數功能。

順便也可以瞭解下,有的boost庫的大部分接口不用事先編譯成庫,只需包含頭文件就可以直接使用,比如data_time庫,而有的庫必需先編譯成庫文件,然後纔可以使用,比如filesystem庫。這是因爲 data_time庫的大部分接口實現都在boost_1_44_0\boost\date_time目錄下的頭文件中,而filesystem庫除了boost_1_44_0\boost\目錄下的頭文件實現了部分接口外,其他大部分都放在libs\filesystem\v3\src\目錄下。這個目錄下的文件都是cpp文件,正常情況下是需要編譯成庫才能使用的。當然特殊情況下也可以把這些cpp文件包含到自己的工程中去,直接在自己的工程中編譯實現,這樣的好處是完全跨平臺(因爲都不用事先編譯成相應平臺的庫了)但這樣也會付出代價,編譯時間會很長、工程的代碼量非常大且很多接口是用不上的。

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章