C++标准输入输出流库之移花接木

anrxhzh 2002-07-04 05:05:45
曾经见过一个帖子,问如何用C\C++标准输入输出库实现lock file的功能。恰好我也碰到了类似的问题,思考了一下,觉得这是一个具有普遍意义的问题。实际上早期的标准库是支持lock file的,后来由于兼容性的问题取消了这个功能。我们知道,每个操作系统都提供了一套文件操作的API,C\C++标准库中支持的功能只能是所有操作系统API的交集,如果我们需要这个交集以外的功能,同时又希望能最大限度地利用标准库,那么该如何做呢?

实际上,标准库任何的文件操作最终都是通过操作系统提供的API来完成的,我们只需要将库中的抽象类型和底层的FILE HANDLE做一个一一映射就解决了这个问题,下面的文档详细地介绍了WIN32系统下如何完成映射。
http://www.codeproject.com/file/handles.asp

我要补充两点:
1.文档的方法同样适用于UNIX的文件描述符。
2.在抽象层和操作系统的映射的两端要分别做一次Clearup,确保提交给对方的是一个干净的对象。这样就可以保证这两个层次不会发生任何冲突。
...全文
66 点赞 收藏 7
写回复
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
pi1ot 2002-07-05
谢谢.
回复
anrxhzh 2002-07-04
终于成功了。需要说明的是:
1.下面的例子只给出了basic_ifstream,还需要改写basic_ofstream和basic_fstream,不过是大同小异的工作。
2.当移植到UNIX平台时,需要改写例子中和操作系统中有关的部分。
3.算了算,我仅仅增加了11行代码就完成了对std::basic_ifstream的改造,这种改造对标准库是完全透明的,即使加上另外两个类也不超过50行的代码量,却获得了操作系统底层的文件句柄,使得移花接木成为可能。

#include <fstream>

namespace ashura {

// TEMPLATE CLASS basic_ifstream
template<class _E, class _Tr = char_traits<_E> >
class basic_ifstream : public std::basic_istream<_E, _Tr> {
public:
typedef basic_ifstream<_E, _Tr> _Myt;
typedef std::basic_filebuf<_E, _Tr> _Myfb;
basic_ifstream()
: std::basic_istream<_E, _Tr>(&_Fb) {}

//explicit basic_ifstream(const char *_S,
// std::ios_base::openmode _M = in)
// : std::basic_istream<_E, _Tr>(&_Fb)
// {if (_Fb.open(_S, _M | in) == 0)
// setstate(failbit); }

///////// my code begin /////////
explicit basic_ifstream(const char *_S,
std::ios_base::openmode _M = in)
: std::basic_istream<_E, _Tr>(&_Fb), _file(_S, _M | in), _Fb(_file.f)
{if (!_file.isopen())
setstate(failbit); }
FILE* get_handle() { return _file.f; }
///////// my code end /////////

virtual ~basic_ifstream()
{}
_Myfb *rdbuf() const
{return ((_Myfb *)&_Fb); }
bool is_open() const
{return (_Fb.is_open()); }
void open(const char *_S, std::ios_base::openmode _M = in)
{if (_Fb.open(_S, _M | in) == 0)
setstate(failbit); }
void open(const char *_S, std::ios_base::open_mode _M)
{open(_S, (openmode)_M); }
void close()
{if (_Fb.close() == 0)
setstate(failbit); }
private:
///////// my code begin /////////
struct osfile{
osfile(const char *_S, std::ios_base::openmode _M) : f(std::__Fiopen(_S, _M)) { };
bool isopen() { return f!=0; }
FILE* f;
} _file;
///////// my code end /////////
_Myfb _Fb;
};

typedef basic_ifstream<char, std::char_traits<char> > ifstream;

}


#include <string>
#include <iostream>
#include <windows.h>
#include <io.h>

int main()
{
ashura::ifstream f("c:\\test.txt");

HANDLE hFile = reinterpret_cast<HANDLE>(_get_osfhandle(f.get_handle()->_file));
BY_HANDLE_FILE_INFORMATION file_info;
BOOL bSuccess = GetFileInformationByHandle(hFile,&file_info);

using namespace std;
string str;
f >> str;
cout << bSuccess << " " << str << endl;
}

//output:
//1 hello


回复
LeeMaRS 2002-07-04
自问自答?.....高人! STRONG!

回复
anrxhzh 2002-07-04
嘿嘿,还有一招,自己写一个my_fstream:public basic_istream;估计还比较简单,因为我们需要的仅仅是保存一个操作系统文件句柄而已。如果成功了,我会将代码帖在这里,也欢迎有兴趣的朋友指点。修炼去也。
回复
guopo 2002-07-04
up!
回复
anrxhzh 2002-07-04
看来只好自己写一个文件类了。
不如意事十八九。
回复
anrxhzh 2002-07-04
进一步的研究发现,只有在老的fstream中才能取得底层的文件句柄;新的C++标准库已经将句柄封装到了basic_filebuf的实现细节中,不可能得到了。结论是:如果使用了新的标准库,就不要动这种和操作系统底层移花接木的念头了。
回复
发动态
发帖子
C语言
创建于2007-09-28

6.3w+

社区成员

C语言相关问题讨论
申请成为版主
社区公告
暂无公告