多层目录文件抽取到单个目录
描述:将含有多层子目录的某个目录下的全部文件,抽取到某个目录下(无子目录)。
举例:C:\abc为目录,Dir0、Dir1为C:\abc下的子目录
C:\abc
| a.doc
| b.doc
| +---Dir0
| c.doc
| d.doc
| e.doc
| +---Dir1
| e.doc
假设抽取到C:\def目录,a.doc等文件在C:\def目录下
C:\def
| a.doc
| b.doc
| c.doc
| d.doc
| e.doc
| e(1).doc
说明:
1)多线程实现,一个搜索线程,一个拷贝线程
2)搜索线程中搜索文件时,使用FindFirstFile/FindNextFile/FindClose函数
3)两个线程之间用一个链表来交换数据,自定义并实现数据结构,不允许使用C++ STL和系统自带的一些数据结构
4)两个线程同步运行,使用信号量实现线程同步,关键区域实现对链表的保护
5)如果需要动态内存分配,使用HeapAlloc/HeapFree实现
6)创建线程使用Windows API,不使用Run-Time Library函数
程序形式:Visual C++ / Win / Win 32 项目/Windows 应用程序
#include "stdio.h"
#include "windows.h"
struct PathNode{
//源文件路径
char srcFilePath[MAX_PATH];
//目的文件路径
char desFilePath[MAX_PATH];
struct PathNode *next;
};
struct Queue{
PathNode *front,*rear;
};
HANDLE g_hSemaphore = NULL;
CRITICAL_SECTION g_cs = {0};
char srcPath[MAX_PATH],desPath[MAX_PATH],tempPath[MAX_PATH];
Queue *pathQueue;
//将源文件路径和目的文件路径作为节点插入到队列中
void insertPath(char *spath,char *dpath){
//进入临界区
EnterCriticalSection(&g_cs);
printf("搜到文件%s\n",spath);
PathNode *pNode = (PathNode *)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, sizeof(PathNode));
strcpy(pNode->srcFilePath,spath);
strcpy(pNode->desFilePath,dpath);
pNode->next=NULL;
if(pathQueue->rear == NULL && pathQueue->front == NULL)
pathQueue->front = pathQueue->rear= pNode;
else{
pathQueue->rear->next = pNode;
pathQueue->rear = pNode;
}
//退出临界区
LeaveCriticalSection(&g_cs);
ReleaseSemaphore(g_hSemaphore,1,NULL);
}
//从队列中将源文件路径和目的文件路径取出来
void getPath(char *spath,char *dpath){
//进入临界区
EnterCriticalSection(&g_cs);
strcpy(spath,pathQueue->front->srcFilePath);
strcpy(dpath,pathQueue->front->desFilePath);
printf("拷贝文件%s\n",spath);
PathNode *p = pathQueue->front;
if( pathQueue->front == pathQueue->rear)
pathQueue->front = pathQueue->rear =NULL;
else
pathQueue->front = pathQueue->front->next;
HeapFree(GetProcessHeap(), 0, p);
//退出临界区
LeaveCriticalSection(&g_cs);
}
//递归遍历目录
void findFile(char *path){
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
char pathSearch[MAX_PATH];
hFind = FindFirstFile(path, &FindFileData);
//查找path目录下的第一个文件
if (hFind == INVALID_HANDLE_VALUE){
printf ("Invalid File Handle. Get Last Error reports %d\n", GetLastError ());
exit(-1);
}
//判断查找到的文件属性是否为目录,如果是目录,
//将当前路径加上目录的文件名,递归调用findFile,深搜
if(FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY){
if(FindFileData.cFileName[0] != '.'){
strcpy(pathSearch,path);
pathSearch[strlen(pathSearch)-1]='\0';
strcat(pathSearch,FindFileData.cFileName);
//printf("<DIR> %s\n",pathSearch);
strcat(pathSearch,"\\\*");
findFile(pathSearch);
}
}else{
//查找到的文件不是目录就直接打印出来,并将文件的路径作为节点插入到
//自定义的链队列中,插入结束后释放信号量
strcpy(pathSearch,path);
pathSearch[strlen(pathSearch)-1]='\0';
strcat(pathSearch,FindFileData.cFileName);
strcpy(tempPath,desPath);
strcat(tempPath,FindFileData.cFileName);
//printf("%s\n",tempPath);
insertPath(pathSearch,tempPath);
}
//查找目录下的其他文件,步骤相似
while(FindNextFile(hFind, &FindFileData)){
if(FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY){
if(FindFileData.cFileName[0] != '.'){
strcpy(pathSearch,path);
pathSearch[strlen(pathSearch)-1]='\0';
strcat(pathSearch,FindFileData.cFileName);
//printf("<DIR> %s\n",pathSearch);
strcat(pathSearch,"\\\*");
findFile(pathSearch);
}
}else{
strcpy(pathSearch,path);
pathSearch[strlen(pathSearch)-1]='\0';
strcat(pathSearch,FindFileData.cFileName);
strcpy(tempPath,desPath);
strcat(tempPath,FindFileData.cFileName);
//printf("%s\n",tempPath);
insertPath(pathSearch,tempPath);
//ReleaseSemaphore(g_hSemaphore,1,NULL);
}
}
FindClose(hFind);
}
//给目标目录下重名的文件重命名
void reName(char *path){
WIN32_FIND_DATA FileData;
while(FindFirstFile(path, &FileData) != INVALID_HANDLE_VALUE){
char *ptr = strrchr(path,'.');
char temp[10];
strcpy(temp,ptr);
path[ptr-path]='\0';
strcat(path,"(1)");
strcat(path,temp);
}
}
//用来搜索文件的线程处理函数
DWORD WINAPI ThreadSend(LPVOID pParam){
findFile(srcPath);
return 0;
}
//用来拷贝文件的线程处理函数
DWORD WINAPI ThreadRecv(LPVOID pParam){
while(1){
//等待信号量,如果队列中没有节点,线程一直等待
WaitForSingleObject(g_hSemaphore,INFINITE);
//用来从队列中获取源文件路径和目的文件路径
char s[MAX_PATH],d[MAX_PATH];
getPath(s,d);
reName(d);
CopyFile(s,d,true);
}
return 0;
}
//创建2个线程
void create(){
DWORD nThreadID = 0;
HANDLE hThread[2] = {NULL};
hThread[0] = CreateThread(NULL,0,ThreadSend,NULL,0,&nThreadID);
hThread[1] = CreateThread(NULL,0,ThreadRecv,NULL,0,&nThreadID);
WaitForMultipleObjects(2,hThread,true,INFINITE);
}
int main(int argc, char* argv[])
{
g_hSemaphore=CreateSemaphore(NULL,0,200,NULL);
InitializeCriticalSection(&g_cs);
pathQueue = (Queue *)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, sizeof(Queue));
pathQueue->front = pathQueue->rear = NULL;
printf("输入源目录的路径(例如E:\\interview\\\*):");
scanf("%s",srcPath);
printf("输入目的目录的路径(例如E:\\abc\\):");
scanf("%s",desPath);
//创建线程
create();
DeleteCriticalSection(&g_cs);
CloseHandle(g_hSemaphore);
return 0;
}