受够了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);
}
![](http://tiebapic.baidu.com/forum/w%3D580/sign=f7e62990a5119313c743ffb855390c10/f50905eff01f3a298950329c8e25bc315d607ca3.jpg?tbpicau=2025-02-25-05_aeb37309778e6fab14a5e593938642ed)
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);
}
![](http://tiebapic.baidu.com/forum/w%3D580/sign=f7e62990a5119313c743ffb855390c10/f50905eff01f3a298950329c8e25bc315d607ca3.jpg?tbpicau=2025-02-25-05_aeb37309778e6fab14a5e593938642ed)