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文件包含到自己的工程中去,直接在自己的工程中编译实现,这样的好处是完全跨平台(因为都不用事先编译成相应平台的库了)但这样也会付出代价,编译时间会很长、工程的代码量非常大且很多接口是用不上的。

 


 

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