• 除虫记——有关WindowsAPI文件查找函数的一次压力测试


    作者:朱金灿

    来源:http://blog.csdn.net/clever101

     

            这里说的除虫是指排除bug的意思。今天排除了一个有意思的bug,其中的场景大致是这样的:现在你要统计一个文件夹下非隐藏文件的数目(包含它的子文件夹),很快你写出这样的代码:

    //dirName ——文件夹路径
    //nImgNum ——文件数量
    bool StatFiles(std::string& dirName,int& nImgNum)
    {
    	std::string tempFileFind = dirName + _T("\*") ;
    
    	HANDLE hFind = INVALID_HANDLE_VALUE;
    	WIN32_FIND_DATA ffd;
    	hFind = FindFirstFile(tempFileFind.c_str(), &ffd);
    	if (hFind != INVALID_HANDLE_VALUE)
    	{
    		do
    		{
    			tString strSub = dirName + _T("\") + ffd.cFileName;
    			if (((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)==0)
    				&&((ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)==0))
    			{
                    nImgNum++; 
    			}
    		}while (FindNextFile(hFind, &ffd) != 0);
    	}
    	else
    	{
    		return false;
    	}
    
    	tempFileFind = dirName + _T("\*");
    	hFind = INVALID_HANDLE_VALUE;
    
    	hFind = FindFirstFile(tempFileFind.c_str(), &ffd);
    	if (hFind != INVALID_HANDLE_VALUE)
    	{
    		do
    		{
    			if (ffd.cFileName[0] == '.')
    			{
    				if (ffd.cFileName[1] == '' ||
    					(ffd.cFileName[1] == '.' &&
    					ffd.cFileName[2] == ''))
    				{
    					continue;
    				}
    			}
    
    			std::string strSub = dirName + _T("\") + ffd.cFileName;
    			if (!((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)==0))
    			{
    				StatFiles(strSub,nImgNum);
    			}
    
    		}while (FindNextFile(hFind, &ffd) != 0);
    	}
    
    	return true;
    }
    


             然后拿一个文件夹来测试,嗯,测试没有问题,返回的数目也是对的。然后我们拿一个包含很多子文件夹和文件来测试,发现运行到文件数是七千多的时候函数就返回false了。开始我们比较迷惑,后来发现问题了,原来是忘记关闭文件查找句柄了,当统计达到七千多的时候已经把windows的查找句柄资源消耗尽了。我感觉这真是对WindowsAPI文件查找函数的一次压力测试。正确的代码应该是这样的:

    //dirName ——文件夹路径
    //nImgNum ——文件数量
    bool StatFiles(std::string& dirName,int& nImgNum)
    {
    	std::string tempFileFind = dirName + _T("\*") ;
    
    	HANDLE hFind = INVALID_HANDLE_VALUE;
    	WIN32_FIND_DATA ffd;
    	hFind = FindFirstFile(tempFileFind.c_str(), &ffd);
    	if (hFind != INVALID_HANDLE_VALUE)
    	{
    		do
    		{
    			tString strSub = dirName + _T("\") + ffd.cFileName;
    			if (((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)==0)
    				&&((ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)==0))
    			{
                    nImgNum++; 
    			}
    		}while (FindNextFile(hFind, &ffd) != 0);
    	}
    	else
    	{
    		return false;
    	}
        FindClose(hFind); //记得关闭文件查找句柄
    
    	tempFileFind = dirName + _T("\*");
    	hFind = INVALID_HANDLE_VALUE;
    
    	hFind = FindFirstFile(tempFileFind.c_str(), &ffd);
    	if (hFind != INVALID_HANDLE_VALUE)
    	{
    		do
    		{
    			if (ffd.cFileName[0] == '.')
    			{
    				if (ffd.cFileName[1] == '' ||
    					(ffd.cFileName[1] == '.' &&
    					ffd.cFileName[2] == ''))
    				{
    					continue;
    				}
    			}
    
    			std::string strSub = dirName + _T("\") + ffd.cFileName;
    			if (!((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)==0))
    			{
    				StatFiles(strSub,nImgNum);
    			}
    
    		}while (FindNextFile(hFind, &ffd) != 0);
    	}
        FindClose(hFind); //记得关闭文件查找句柄
    
    	return true;
    }

           如何避免这种资源泄漏的问题的发生?首先需要明确你要申请的是一种资源,在使用资源之前需要明确在哪儿释放掉资源从而避免资源泄漏。

  • 相关阅读:
    Spring 总结
    分布式缓存Memcache
    Docker原理 -- namespace与CGroup
    JDK源码分析--Collections
    React生命周期总结
    【转】前端优化的35条
    http缓存与cdn相关技术
    跨域处理
    sequekize
    orm2
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6469927.html
Copyright © 2020-2023  润新知