网页资讯视频图片知道文库贴吧地图采购
进入贴吧全吧搜索

 
 
 
日一二三四五六
       
       
       
       
       
       

签到排名:今日本吧第个签到,

本吧因你更精彩,明天继续来努力!

本吧签到人数:0

一键签到
成为超级会员,使用一键签到
一键签到
本月漏签0次!
0
成为超级会员,赠送8张补签卡
如何使用?
点击日历上漏签日期,即可进行补签。
连续签到:天  累计签到:天
0
超级会员单次开通12个月以上,赠送连续签到卡3张
使用连续签到卡
06月25日漏签0天
图形编程forc吧 关注:14贴子:296
  • 看贴

  • 图片

  • 吧主推荐

  • 游戏

  • 1回复贴,共1页
<<返回图形编程forc吧
>0< 加载中...

文件搜索与匹配算法中一个诡异问题的解决

  • 只看楼主
  • 收藏

  • 回复
  • hellovfp
  • 排序查找
    6
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
受够了win8文件查找的不爽,只好自己实现文件和文本内容搜索,写好了主要算法结构,结果无意中在XP中测试时出现一个诡异的bug,在调试时,单步调试时,会在扫描文件函数调用时挂掉,但不调试,直接运行又能成功运行,在win8中又不存在这个问题,代码如下:
class FileInfo
{
HANDLE hFind;
typedef WIN32_FIND_DATAA finfo;
typedef SYSTEMTIME ftime;
public:
finfo info;
ftime time;
~FileInfo()
{
if(hFind!= INVALID_HANDLE_VALUE)
FindClose(hFind);//不要二次调用,会引起死循环的
}
//文件搜索
bool find(const char* findstr)
{
hFind = FindFirstFileA(findstr, &info);
return hFind != INVALID_HANDLE_VALUE;
}
bool next()
{
return FindNextFileA(hFind, &info) > 0;
}
//文件时间转换
void create_time()
{
FileTimeToSystemTime(&info.ftCreationTime, &time);
}
void access_time()
{
FileTimeToSystemTime(&info.ftLastAccessTime, &time);
}
void write_time()
{
FileTimeToSystemTime(&info.ftLastWriteTime, &time);
}
void close()
{
FindClose(hFind);
}
bool is_dir()
{
return (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)>0;
}
};
扫描函数:
void scan_dir2(const char*path)
{
static char sub[MAX_PATH];
FileInfo fi;
char *p = copystr(sub, MAX_PATH, path);
if(*(p-1) != '/'){
*p++ = '/';
}
copystr(p, MAX_PATH-(p-sub), "*");
if(!fi.find(sub)) return;
*p=0;
do
{
if(fi.info.cFileName[0] == '.' /*|| fi.info.cFileName[0]=='$'*/) continue;
if(fi.is_dir()){
copystr(p, MAX_PATH-(p-sub), fi.info.cFileName);
//printf("dir:%s,%#x\n", sub, fi.info.dwFileAttributes);
scan_dir2(sub);
}
else{
scan_do(fi.info.cFileName, sub);
}
}while(fi.next());
//fi.close();这里会挂掉
}
调试了一下,发现进入一个子目录后,列举文件完成,返回后就会在fi.close()这句挂掉,让人抓狂,静下心来,仔细起了一下,想起最近添加了析构函数,多半应该是二次释放资源引起的,于是在close关闭后,将句柄手动复位,问题居然这这样解决了,由此猜想新操作系统可能在这里进行过修改,既使无意中二次释放也不会出错。
然后从Java的一个字符串匹配算法,重写成C++版的,由于Java里没有指针,写出来的代码比c++的好看,我改写了一个下标版和一个指针版,实际测试,指针版的最快,这里给出指针版的:
bool is_match4(const char*s, const char *p)
{
const char *ms = 0, *mp = 0;//记录匹配到'*'的位置
while(*s)
{
if(*p && (tolower(*s) == tolower(*p) || *p == '?')){//直接字符匹配或p里是'?'
++s;
++p;
}
else if(*p == '*'){//是'*'时, 记录当前指针位置,并且先把j指针走一步
ms = s;
mp = p++;
}
else if(mp){//j走一步后和i不匹配, 则需要用'*'匹配掉当前i,所有i走一步,j退一步, 再继续比较
s = ++ms;
p = mp + 1;
}
else//没有完全匹配或者匹配不正确
return false;
}
while(*p)//s已经完全匹配完, 但是j指针还没有走完的情况
if(*p++ != '*') return false;
return true;
}
配合上面的基础文件扫描框架,可以实现遍历任意目录指定文件:
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <ctype.h>
class FileInfo
{
HANDLE hFind;
typedef WIN32_FIND_DATAA finfo;
typedef SYSTEMTIME ftime;
public:
finfo info;
ftime time;
~FileInfo()
{
if(hFind!= INVALID_HANDLE_VALUE)
FindClose(hFind);//不要二次调用,会引起死循环的
}
//文件搜索
bool find(const char* findstr)
{
hFind = FindFirstFileA(findstr, &info);
return hFind != INVALID_HANDLE_VALUE;
}
bool next()
{
return FindNextFileA(hFind, &info) > 0;
}
//文件时间转换
void create_time()
{
FileTimeToSystemTime(&info.ftCreationTime, &time);
}
void access_time()
{
FileTimeToSystemTime(&info.ftLastAccessTime, &time);
}
void write_time()
{
FileTimeToSystemTime(&info.ftLastWriteTime, &time);
}
bool is_dir()
{
return (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)>0;
}
};
int istrcmp(const char*s1, const char* s2)
{
char ch1, ch2;
do{
ch1 = *s1++;
ch2 = *s2++;
if(ch1 >= 'A' && ch1 <= 'Z') ch1 +=32;
if(ch2 >= 'A' && ch2 <= 'Z') ch2 +=32;
}while(ch1 && ch2 && ch1 == ch2);
return ch1 - ch2;
}
template<typename T>
T* copystr(T* dst, int size, const T* s)
{
while(--size> 0 && *s)
*dst++ = *s++;
*dst = 0;
return dst;
}
bool is_match4(const char*s, const char *p)
{
const char *ms = 0, *mp = 0;//记录匹配到'*'的位置
while(*s)
{
if(*p && (tolower(*s) == tolower(*p) || *p == '?')){//直接字符匹配或p里是'?'
++s;
++p;
}
else if(*p == '*'){//是'*'时, 记录当前指针位置,并且先把j指针走一步
ms = s;
mp = p++;
}
else if(mp){//j走一步后和i不匹配, 则需要用'*'匹配掉当前i,所有i走一步,j退一步, 再继续比较
s = ++ms;
p = mp + 1;
}
else//没有完全匹配或者匹配不正确
return false;
}
while(*p)//s已经完全匹配完, 但是j指针还没有走完的情况
if(*p++ != '*') return false;
return true;
}
static int count = 0;
void show_zip(const char* s)
{
const char *p = strrchr(s, '.');
if(p){
++p;
if(istrcmp(p, "rar")==0 || istrcmp(p, "zip") == 0){
puts(s);
++count;
}
}
}
static void(*scan_do)(const char* name, const char* path);
void init_scan(void(*pfun)(const char*, const char*))
{
scan_do = pfun;
}
void scan_dir2(const char*path)
{
static char sub[MAX_PATH];
FileInfo fi;
char *p = copystr(sub, MAX_PATH, path);
if(*(p-1) != '/'){
*p++ = '/';
}
copystr(p, MAX_PATH-(p-sub), "*");
if(!fi.find(sub)) return;
*p=0;
do
{
if(fi.info.cFileName[0] == '.' /*|| fi.info.cFileName[0]=='$'*/) continue;
if(fi.is_dir()){
copystr(p, MAX_PATH-(p-sub), fi.info.cFileName);
//printf("dir:%s,%#x\n", sub, fi.info.dwFileAttributes);
scan_dir2(sub);
}
else{
scan_do(fi.info.cFileName, sub);
}
}while(fi.next());
//fi.close();
}
#include <time.h>
void show_all(const char*s, const char* path)
{
puts(s);
++count;
}
void show_cpp(const char*s, const char* path)
{
const char *p = strrchr(s, '.');
if(p){
++p;
if(istrcmp(p, "c")==0 || istrcmp(p, "cpp") == 0){
puts(s);
++count;
}
}
}
static char *filters[] = {"*.txt"/*, "*.d2s", "*.mp3"*/};
void show_filter(const char*s, const char* path)
{
bool ret = false;
for(int i = 0; i < 1; ++i){
if(is_match4(s, filters[i])){
ret = true;
break;
}
}
//if(is_match4(s, filters[0]) || is_match4(s, filters[1]))
//ret = true;
if(ret){
//printf("%s%s\n", path, s);
char buf[MAX_PATH], *p;//这种写法比printf还快
p = copystr(buf, MAX_PATH, path);
copystr(p, MAX_PATH-(p-buf), s);
puts(buf);
++count;
}
}
void chdir(const char*s)
{
SetCurrentDirectoryA(s);
}
template<typename T>
void replace_all(T* s, T sch, T x)
{
for(;*s; ++s){
if(*s == sch) *s = x;
}
}
void test_copy()
{
char d[20], s[] = "****", *p;
p = copystr(d, 20, s);
printf("%s, %d\n", d, p-d);
}
int main(int argc, char* argv[])
{
double time;
clock_t start = clock();
init_scan(show_filter);
if(argc == 2){
//chdir(argv[1]);
replace_all(argv[1], '\\', '/');
scan_dir2(argv[1]);
}
else
scan_dir2("z:");
time = clock()-start;
printf("scan use %.3f\n%d files\n", time/ 1000, count);
}


  • hellovfp
  • 排序查找
    6
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
再说一下程序中关于拷贝字符串,记得有人在C吧里论拷贝函数手写无须返回指针,简直不敢苟同,实际上上述程序示范了无需调用strcat,只用手写的copystr,返回复制后的尾指针,可以方便的实现路径字符串和文件名串的合并。
template<typename T>
T* copystr(T* dst, int size, const T* s)
{
while(--size> 0 && *s)
*dst++ = *s++;
*dst = 0;
return dst;
}
调用示例:
void show_filter(const char*s, const char* path)
{
bool ret = false;
for(int i = 0; i < 1; ++i){
if(is_match4(s, filters[i])){
ret = true;
break;
}
}
//if(is_match4(s, filters[0]) || is_match4(s, filters[1]))
//ret = true;
if(ret){
//printf("%s%s\n", path, s);
char buf[MAX_PATH], *p;//这种写法比printf还快
p = copystr(buf, MAX_PATH, path);
copystr(p, MAX_PATH-(p-buf), s);
puts(buf);
++count;
}
}
这种合并方式比用printf("%s%s\n", path, s)还要快。
所以当库函数并不符合我们的要求的时候,还是自己手写的比较好。


登录百度账号

扫二维码下载贴吧客户端

下载贴吧APP
看高清直播、视频!
  • 贴吧页面意见反馈
  • 违规贴吧举报反馈通道
  • 贴吧违规信息处理公示
  • 1回复贴,共1页
<<返回图形编程forc吧
分享到:
©2025 Baidu贴吧协议|隐私政策|吧主制度|意见反馈|网络谣言警示