某公司面试测试题

多层目录文件抽取到单个目录

描述:将含有多层子目录的某个目录下的全部文件,抽取到某个目录下(无子目录)。

举例:C:\abc为目录,Dir0Dir1C:\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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值