一 背景

有个需求,要从大量的文件中过滤需要的文件,文件名那是以时间命令(UTC时间)的,要过滤的文件范围也是符合一定时间段的文件。

二  初始版本

代码比较简单和直接,通过直接读取目录下的文件,获取每个文件的文件名信息,判断每个文件名是否在要求的时间范围内,是的话就放入到文件名列表中,最后返回。这段代码,从感觉上,性能一般,如果有几百万个文件,甚至更多个文件,则每个文件名都要判断一次耗时是惊人的,那能不能根据文件名直接做二分查找的方式来过滤文件名那。

int thisFileNeedSearch(char* fileName, int startTime, int endTime)
{if (fileName == NULL) {return -1;}char* flag = ".";char* ptmp = strdup(fileName);strtok(ptmp, flag);strtok(NULL, flag);char* ret = strtok(NULL, flag);if (ret != NULL) {int iret = atoi(ret);if (iret >= startTime && iret <= endTime) {free(ptmp);return 1;} else {free(ptmp);return 0;}} else {cl_error("file is error:%s", fileName);free(ptmp);return -1;}
}fileLists* getNeedSearchFilesOld(char* dir_name, int startTime, int endTime)
{DIR* dir = opendir(dir_name);struct dirent* p = NULL;struct stat statbuf;fileLists* lst = NULL;cl_infos("Scan dir is:%s", dir_name);if (lstat(dir_name, &statbuf)) {cl_error("Stat error:%s", dir_name);return NULL;}if (!S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {cl_error("Dir :%s is not dir mode is:%d!", dir_name, statbuf.st_mode);return NULL;}while ((p = readdir(dir)) != NULL) {// 过滤掉. 和..if (p->d_name[0] == '.') {continue;}if (thisFileNeedSearch(p->d_name, startTime, endTime) == 1) {if (lst == NULL) {lst = (fileLists*)malloc(sizeof(fileLists));assert(lst != NULL);lst->fileName = strdup(p->d_name);lst->next = NULL;lst->size = 1;lst->tail = lst;} else {fileLists* plst = (fileLists*)malloc(sizeof(fileLists));assert(plst != NULL);plst->fileName = strdup(p->d_name);plst->next = NULL;plst->size = 1;lst->tail->next = plst;lst->tail = plst;lst->size += 1;}} else {cl_debug("file:%s not in start:%d end:%d", p->d_name, startTime, endTime);}}closedir(dir);return lst;
}

三 二分查找版本

要查找文件的范围是个区间[starttime,endtime],一般endtime和starttime的差值并不算多大,那么我们可以先对文件名做个排序,然后根据二分查找的算法,查找到开始遍历starttime的文件名,逐步对后遍历即可。

直接读目录的方式,在排序挺麻烦,幸好linux有另外一个遍历文件的接口如下:

#include <dirent.h>int scandir( const char *dir,  struct dirent **namelist,  int (*filter) (const void *b),  int ( * compare )( const struct dirent **, const struct dirent ** ) );
int alphasort(const void *a, const void *b);
int versionsort(const void *a, const void *b);

提供两个接口,一个是filter接口,即过滤需要的文件名,二是比较接口,即比较排序的时候使用,我们可以直接使用alphasort进行文件名的比较。如下:

// 保留文件名中包含file的文件
int file_filter(const struct dirent* dir)
{const char* name = dir->d_name;int len = strlen(name);if (MIN_FILE_NAME_LEN > len) {return 0;} else {char* pos = strstr(dir->d_name, "file");if (pos == NULL) {return 0;} else {return 1;}}
}fileLists* getNeedSearchFiles(char* dir_name, int startTime, int endTime)
{struct dirent** entry_list = NULL;int count = scandir(dir_name, &entry_list, pcap_filter, alphasort);cl_infos("files number:%d", count);if (count < 1) {cl_infos("No find file is dir:%d", dir_name);return NULL;}int fileStart = fileNameToInt(entry_list[0]->d_name);cl_infos("start filename:%s", entry_list[0]->d_name);// 最小值大于要查询的最大值 直接返回if (fileStart > endTime) {freeEntryList(entry_list, count);free(entry_list);cl_infos("file start time:%d is bigger than endtime:%d", fileStart, endTime);return NULL;}if (count > 1) {// 最大值比最小值都小 直接返回int fileEnd = fileNameToInt(entry_list[count - 1]->d_name);cl_infos("end filename:%s", entry_list[count - 1]->d_name);if (fileEnd < startTime) {freeEntryList(entry_list, count);free(entry_list);cl_infos("file end time:%d is small than start:%d", fileEnd, startTime);return NULL;}}int low = 0;int high = count - 1;fileLists* lst = NULL;int startIndex = 0;// 二分查找文件范围while (low <= high) {int mid = low + (high - low) / 2;struct dirent* entry = entry_list[mid];int filetime = fileNameToInt(entry->d_name);// 说明要取得范围在左边if (filetime > startTime) {startIndex = mid;high = mid - 1;cl_infos("set startIndex:%d", startIndex);}// 说明文件范围在右边else if (filetime < startTime) {low = mid + 1;} else {// 找到最小值了startIndex = mid;break;}}for (int j = startIndex; j < count; j++) {int filetime = fileNameToInt(entry_list[j]->d_name);if (filetime >= startTime && filetime <= endTime) {addToFileList(&lst, entry_list[j]->d_name);}}freeEntryList(entry_list, count);free(entry_list);return lst;
}

说明下 :  int mid = low + (high - low) / 2; 只所以有这种写法是为了防止low+high越界。

代码不算啥,给大家一个二分查找一段范围的文件的一点思路吧。

四 测试

写完了,免不了测试下,结果有点令人惊讶,如果文件数目少于9万个,其实老版本的性能反而更好,差别不是特别大,原因是scandir的过滤和排序拉慢了速度,而且核心逻辑只是转int和比较,在较小的数量级下,二分查找的性能不一定好于普通的查找。

五 诗词鉴赏

满庭芳·赠于瓦罐先生朝代:[元代] 作者:[马钰] 有荣有辱,有利有害。有喜有忧相待。
有得有失,自是有成有败。为人有生有死,但有形、必然有坏。休著有,自古来著,有有谁存在。
好认无为无作,道无情无念,无憎无爱。无我无人无染,无著无碍。
无心有消业障,这无无、人还悟解。
无中趣,得无生无灭,超越三界。

二分过滤文件代码分享相关推荐

  1. 如何利用python将mp4文件转换为gif文件 + 代码分享 另附在线转换网址

    https://blog.csdn.net/hanhanwanghaha宝藏女孩 欢迎您的关注! 欢迎关注微信公众号:宝藏女孩的成长日记 如有转载,请注明出处(如不注明,盗者必究) 想要将自己的视频设 ...

  2. php 浏览器 兼容,兼容ie6浏览器的php下载文件代码分享

    PS:这段代码在win系统下跑没有问题,枫哥亲测可用.如果用的是linux或是其他系统,要要诸位自行测试下啦. $filename = "./".$_REQUEST['name'] ...

  3. 二分算法php,使用PHP实现二分查找算法代码分享

    第一种方法: [二分查找要求]:1.必须采用顺序存储结构 2.必须按关键字大小有序排列. [优缺点]折半查找法的优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难.因 ...

  4. C#强力粉碎文件代码分享,升级中用到

    360的文件粉碎机还是很强大的,在我们客户端winform升级的时候,必须将有些文件进行强力删除后下载更新,如果删除失败很有可能整个 程序就无法更新到最新的版本,所以这里参考了网上的资料整理了一个文件 ...

  5. python复制文件的代码_python调用cmd复制文件代码分享

    import os def load() : filename = os.getcwd() + r'\fromto.txt' if os.path.isfile(filename) : f = ope ...

  6. 【MATLAB】批量读取图像raw文件(干货代码分享)

    [MATLAB]批量读取图像raw文件(干货代码分享) 1.先学个简单的,读取单张raw文件 matlab代码如下: %图像的基本信息: %512行,640列,像素深度16bit. col=640; ...

  7. Unity 分享 功能 用Unity Native Share Plugin 实现链接、图片、视频等文件的分享+ 安卓 Ios 都可以,代码图文详解

    Unity 分享 功能 用Unity Native Share Plugin 实现链接.图片.视频等文件的分享+ 安卓 Ios 都可以,代码图文详解 前言 环境 效果 一.Unity Native S ...

  8. 百度实体链接比赛后记:行为建模和实体链接(含代码分享)

    作者丨苏剑林 单位丨追一科技 研究方向丨NLP,神经网络 个人主页丨kexue.fm 前几个月曾参加了百度的实体链接比赛 [1],这是 CCKS 2019 的评测任务之一,官方称之为"实体链 ...

  9. HTML编辑器自动过滤代码怎么办,KesionCMS X1百度编辑器过滤html代码的修复方法

    看到论坛里,经常有人发帖说,X1采用的百度编辑器,过滤html代码太严重! 现在把修复方法分享如下: 打开editor下的ueditor.all.js文件 1.将9950行左右的allowDivTra ...

最新文章

  1. MySQL CURDATE() 函数
  2. 使用mintty(_如何使用Mintty改善Cygwin控制台
  3. TableStore发布多元索引功能,打造统一的在线数据平台
  4. 自制简单表单验证relative与absolute定位
  5. css表示屏幕宽度和高度
  6. center os php,Center OS 7 Apache安装配置
  7. python 获取二维数组所有元素
  8. 计算机的用户软件在哪,电脑自带录屏软件在哪?这里教你怎么找
  9. es java 实现should must filter组合查询
  10. ISO20001文件清单
  11. SAS实验2——假设检验
  12. matlab分簇教程,分簇算法matlab
  13. redis keys命令,生产环境慎用,最好屏蔽掉
  14. html5ify插件,漂亮的jQuery对话框插件Dialogify
  15. 对话框程序, 在 OnInitDialog的最后 showWindow(SW_HIDE),不管用的原因
  16. 企业研发人员配备比例_如何理解高新技术企业认定对研发人员比例的要求
  17. 新保险时代,技术即是保险,如水滋养万物——新保险
  18. Cadence IC618使用
  19. CS5266Typec转HDMI+PD+U2+U3多口拓展坞设计原理图
  20. 基于javaweb的电影售票系统设计和实现(java+springboot+ssm+mysql+jsp)

热门文章

  1. C语言:从键盘上输入10个整数,求他们的平均值以及正数的个数,并加以输出
  2. 堆漏洞挖掘——fastbin attack漏洞
  3. 再度联手中国联通,开启第二个五年战略合作!
  4. 电脑报,轻薄本中的西装暴徒:机械革命Code01评测
  5. 寂寞是因为思念谁(校园民谣)铃声 寂寞是因为思念谁(校园民谣)...
  6. Linux 抓取网页实例(shell+awk)
  7. 怎么用手机里的计算机玩游戏,黑鲨手机怎么玩电脑上游戏
  8. AS+kotlin+SurfaceView最佳实践之打造六子棋小游戏
  9. HBuilder如何在真机运行
  10. 回归模型评价指标-SST、SSR、SSE、R-square