http://www.toquick.com/index.php/archives/66
Posted on 5月 26th, 2008 作者 cheng
最近在写一个windows客户端,其中需要对一个目录进行遍历,并进行某些操作。
使用C++,我采用模板函数,通过自定义的Action完成对遍历中各种文件目录的特定操作。
其代码如下:
// lpEntry 扫描的目录
// level 扫描的深度,LEVEL_INFINATE表示扫描所有的文件
// action 模板参数实例(functor),执行特定动作
#define LEVEL_INFINATE 0xFFFFFFFF
template< class PredAction >
int dir_scan( LPCTSTR lpEntry, UINT level, PredAction& action)
{
static UINT glevel = 0;
if( level != LEVEL_INFINATE )
{
if( glevel++ > level ) return 1;
}
if( !lpEntry || _tcslen(lpEntry) <= 0 ) return -1;
if( _taccess( lpEntry, 0 ) != 0 ) //目录或文件存在
{
return -1;
}
struct _stat sb;
if( _tstat( lpEntry, &sb ) != 0 ) // 获取信息失败
{
return -2;
}
if( !(sb.st_mode | _S_IFDIR) ) //不是目录
{
return -3;
}
// 开始遍历
tstring sDir = lpEntry;
if( sDir.at( sDir.length()-1) != _T('//') )
sDir.push_back(_T('//'));
tstring sFind = sDir + _T("*.*");
struct _tfinddata_t fd;
intptr_t handle = _tfindfirst( const_cast<LPTSTR>(sFind.c_str()), &fd );
if( handle == -1 ) return -1;
int nFind = 0;
while( nFind == 0 )
{
if ( _tcscmp(fd.name,_T(".")) != 0 && _tcscmp(fd.name, _T("..")) != 0 )
{
if( fd.attrib & _A_SUBDIR ) // 子目录
{
tstring strSubDir = sDir+fd.name;
action( strSubDir.c_str(), false );
dir_scan( strSubDir.c_str(),
level==LEVEL_INFINATE?level:level+1, action );
}
else // 文件
{
action( tstring( sDir+fd.name).c_str(), true );
}
}
nFind = _tfindnext( handle, &fd );
}
_findclose( handle );
return 0;
};
这个时候我用erlang实现了同样功能的目录扫描函数:
-module(dir_scan).
-export([dir_scan/3, test/0, print/2]).
-define(INFINATE_LEVEL, -1).
-include_lib(”kernel/include/file.hrl”).
dir_scan(Path, Level, Action) when is_list(Path), is_function(Action, 2) ->
case file:list_dir(Path) of
{ok, Files} ->
dir_scan(Path, Files, 0, Level, Action);
{error, Reason} ->
{error, {Path, Reason}}
end.
dir_scan(Top, [F | Tail], CurLevel, Level, Action) ->
if
Level == ?INFINATE_LEVEL; CurLevel =< Level ->
F2 = Top ++ “/” ++ F,
case file:read_file_info(F2) of
{ok, FileInfo} when FileInfo#file_info.type == directory -> %% directory
Action(F2, true), % do action
NewLevel = case Level of
?INFINATE_LEVEL ->
Level;
Other ->
Level - 1
end,
case dir_scan(F2, NewLevel, Action) of
ok ->
dir_scan(Top, Tail, CurLevel, Level, Action);
{error, Reason} ->
{error, Reason}
end;
{ok, FileInfo} when FileInfo#file_info.type == regular -> %% normal file
Action(F2, false), % do action
dir_scan(Top, Tail, CurLevel, Level, Action);
_Other ->
dir_scan(Top, Tail, CurLevel, Level, Action)
end;
true ->
ok
end;
dir_scan(_Top, [], _CurLevel, _Level, _Action) ->
ok.
查看两者代码量,相差无几均为60行左右,只是erlang的代码因为没有循环,因此嵌套比较深,不是太美观。
然后看看速度:
erlang版本,我对某个目录进行遍历,对应文件数据不做任何处理,运行10次平均用时77999(microsecond)微妙
C++版本,模板参数Action中operator()为空,平均运行时间为16000微妙。
从中可以看出c++性能为erlang的5倍左右。
erlang采用c实现,而c++与c间的效率差距20%左右,因此c++比erlang运行速度快5倍也不足为其。
这里再次证明了erlang的应用范围及特性,erlang适合分布式程序的开发,开发迅速,容错性好,平台无关,具有成熟的模型。如果没有并发那么erlang存在的意义会大打折扣。