代码质量之——递归删除文件夹

本文通过三个版本的代码实现展示了如何逐步优化一个递归删除文件夹功能,从最初的简单实现到减少内存开销并提高效率的最终版本,并对比了高级语言如Java的简洁实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法执行效率有高有底,数据结构设计有好有坏,代码质量亦可分出优劣,不管哪一个环节的质量好坏,都会影响呈现到用户面前的最终体验。玩过3D网游的童鞋都知道,暴雪的魔兽世界场景优美、画面流畅,加载时间还短、不吃内存(唯一“不足”是角色丑陋),国产3D就逊多了。所以,除了架构设计上有优有劣、算法上存在高明与否,编码上也是有得考究的。实现同样的功能,不同的人写的代码是可以看到差别的,同一个人随着经验的积累也会写出越来越好的代码。以常用到的一个“删除文件夹”功能函数为例,具体看看差别都在哪里。好了,不啰嗦了,且看代码。

第一次用这个功能,是在网上随便索罗了一个版本,略微修改也就采用了:

#include <direct.h>
#include <io.h>
void EA_vDeleteDirectory(const char *DirName)
{
	char acFileUrl[260];
	char acTempDir[260];
	char next_path[260];
	struct _finddata_t fileinfo;
	int findlen;
	int hFile;
	
	memset(acFileUrl, 0x00, sizeof(acFileUrl));
	memset(acTempDir, 0x00, sizeof(acTempDir));
	sprintf(acFileUrl, "%s", DirName);
	if( acFileUrl[strlen(acFileUrl) - 1] != '\\' && acFileUrl[strlen(acFileUrl) - 1] != '/')
	{
		strcat(acFileUrl, "/");
	}
	strcpy(acTempDir, acFileUrl);
	strcat(acFileUrl, "*.*");
	
	findlen = _findfirst(acFileUrl, &fileinfo);
	if(findlen == -1)
	{
		return;
	}
	hFile = findlen;
	
	while (findlen != -1) 
	{
		if (strcmp(fileinfo.name, ".") == 0 || strcmp(fileinfo.name, "..") == 0)
		{
			// 跳过. 和 ..
			findlen = _findnext(hFile, &fileinfo);
			continue;
		}
		
		if (fileinfo.attrib == _A_SUBDIR)
		{
			// 删除子目录
			memset(next_path, 0x00, sizeof(next_path));
			sprintf(next_path, "%s%s", acTempDir, fileinfo.name);
			EA_vDeleteDirectory(next_path);
		}
		else
		{
			memset(next_path, 0, sizeof(next_path));
			sprintf(next_path, "%s%s", acTempDir, fileinfo.name);
			remove(next_path);
		}
		findlen = _findnext(hFile, &fileinfo);
	}
	
	_findclose( hFile );
	rmdir(DirName);
	return;
}
可以看到,每一层递归都会在堆栈上开辟3个260字节长度的临时空间。

后来觉得没必要使用这么多临时变量,第二次使用这个功能时略微进行了改进(Linux C版本):

#include <unistd.h>
#include <dirent.h>
void EA_PUB_vDeleteDirectory(const char *pcDirName)
{
	if(pcDirName == NULL || strlen(pcDirName) == 0)
	{
		return;
	}
	DIR *dir;
    struct dirent *entry;
	char acNextPath[MAX_PATH];
	
    dir = opendir(pcDirName);
    if (dir == NULL)
	{
        return;
    }
	
	while ((entry = readdir(dir)) != NULL)
    {	
		if(strcmp(entry->d_name ,"." ) ==0 || strcmp(entry->d_name ,".." ) ==0 )
		{
			continue;
		}
		
		if (entry->d_type == DT_DIR)
		{
			sprintf(acNextPath, "%s/%s", pcDirName, entry->d_name);
			EA_PUB_vDeleteDirectory(acNextPath);	
		}
		else
        {
			sprintf(acNextPath, "%s/%s", pcDirName, entry->d_name);
			remove(acNextPath);
		}
	}
	closedir(dir);
	remove(pcDirName);
}

这样修改之后,每层递归只需要分配一个MAX_PATH长度的临时空间,于是便心安理得地使用起来。

再后来整理一些基本的功能函数,考虑做成库,希望能够达成“一劳永逸”之效。出于这种考虑便是愿意花费些功夫对里面的每个功能函数细心编码,虽不求完美,但仍然期望在一定范围内做到最好。再次认真审视DeleteDirectory这个函数的时候,可能缘于曾经有接触过Linux下ftw函数的原因,突然来了灵感,最后版本的“递归删除文件夹”函数实现如下:

//删除目录,可能删除失败,对内使用,对外使用的话请选择lib_vDeleteDir
static void DelDirectory(char *pcDirName)
{
	char *pcEnd = NULL;
	struct _finddata_t fileinfo;
	int iFindStart = 0;
	int iFind = 0;
	
	pcEnd = pcDirName + strlen(pcDirName) - 1;
	if( *pcEnd != '/' && *pcEnd != '\\')
	{
		*(++pcEnd) = '/';
	}
	*(++pcEnd) = '\0';
	strcpy(pcEnd, "*.*");
	iFindStart = _findfirst(pcDirName, &fileinfo);
	if(iFindStart == -1)
	{
		return;
	}
	
	iFind = iFindStart;
	while (iFind != -1) 
	{
		if (strcmp(fileinfo.name, ".") == 0 || strcmp(fileinfo.name, "..") == 0)
		{
			// 跳过. 和 ..
			iFind = _findnext(iFindStart, &fileinfo);
			continue;
		}
		
		if (fileinfo.attrib == _A_SUBDIR)
		{
			// 删除子目录
			strcpy(pcEnd, fileinfo.name);
			DelDirectory(pcDirName);
		}
		else
		{
			strcpy(pcEnd, fileinfo.name);
			remove(pcDirName);
		}
		iFind = _findnext(iFindStart, &fileinfo);
	}
	_findclose( iFindStart );
	*pcEnd = '\0';
	rmdir(pcDirName);
	return;
}
//删除整个目录
void lib_vDeleteDir(const char *pcDirName)
{
	char acDir[LEN_1K];
	if(pcDirName == NULL || *pcDirName == '\0')
	{
		return;
	}
	strcpy(acDir, pcDirName);
	DelDirectory(acDir);
}

只需要一次性开辟1024字节长度的存储开销,在基于共同的上一级目录下进行路径的拼接,比较好地实现了同样的功能。

至此,前后3个版本的代码已悉数贴出。

我又在想,越是高级的语言,就越是不需要考虑太多细节,某个功能实现起来就越是省事。如果用Java语言来实现这个功能,基本上会这样写吧:

public static void deleteFile(File file) {
		if(file != null) {
			if (file.isFile()) {
				file.delete();
			} else if (file.isDirectory()) {
				for(File f : file.listFiles()) {
					deleteFile(f);
				}
				file.delete();
			}
		}
	}
   
   public static void emptyDir(File dir) {
		if(dir!=null && dir.isDirectory()) {
			for (File file : dir.listFiles()) {
				deleteFile(file);
			}
		}
	}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值