当前位置:C++技术网 > 资讯 > 根据windows api核心编程,自己练习循环文件夹和文件,程序一两秒后程序就奔溃了

根据windows api核心编程,自己练习循环文件夹和文件,程序一两秒后程序就奔溃了

更新时间:2017-12-14 14:34:13浏览次数:1+次

#include "StdAfx.h"
#include <windows.h>
#include <iostream.h>
#include <string.h>
void getAllFiles(char *dir){
char cFullPath[100];

WIN32_FIND_DATA data;
HANDLE hFind;
strcat(strcpy(cFullPath,dir),"*.*");
hFind=FindFirstFile(cFullPath,&data);
do
{
char cNewDir[100];
if((!strcmp(".",data.cFileName)) || (!strcmp("..",data.cFileName)))
{
continue;
}

if(data.dwFileAttributes==FILE_ATTRIBUTE_DIRECTORY)
{
strcpy(cNewDir,dir);
strcat(cNewDir,data.cFileName);
strcat(cNewDir,"\\\\");
getAllFiles(cNewDir);//递归
}else{
strcpy(cNewDir,dir);
strcat(cNewDir,data.cFileName);
}
cout << cNewDir << endl;
}while(FindNextFile(hFind,&data));
FindClose(hFind);
}
int main(int argc, char* argv[])
{

int DSLength = GetLogicalDriveStrings(0,NULL);
char* DStr = new char[DSLength];
GetLogicalDriveStrings(DSLength,(LPTSTR)DStr);
int DType;
int si=0;
BOOL fResult;
for(int i=0;i<DSLength/4;++i)
{
DType = GetDriveType(DStr+i*4);
if(DType != DRIVE_FIXED)
{
continue;
}
char dir[100]={DStr[si],'''':'''',''''\0''''};
fResult = GetDiskFreeSpaceEx(dir,NULL,NULL,NULL);
if(!fResult)
{
continue;
}

strcat(dir,"\\\\");
getAllFiles(dir);

si+=4;
}
return 0;
}

C++技术网会员解答:

    您好,感谢您对C++技术网的支持与信任。

    首先说声抱歉,有一点耽误了。现在开始为您解答问题。

    程序运行的效果如下:

代码存在几个问题。

1.文件名长度问题

    Windows 通常限定文件名最多包含 260 个字符。但实际的文件名必须少于这一数值,因为完整路径(如 C:\Program Files\filename.txt)都包含在此字符数值中。

    而你代码中的数组长度也就100字节。当遍历的深度比较深的时候,或者一些临时文件的文件名都很长,然后拼起来,都会超过100个字节。这样就会出现大量的字节写入一个指定的内存,然后超出的部分写入到其他内存中,而这些内存不是你程序的空间,所以就被系统阻止了。这样就是产生的内存越界错误。

    问题的根本原因就是给的数组大小不够。在两个变量中都存在长度不够的问题。对于单个文件名是不超过260字符,然后你之类是进行完整路径的拼接,那长度就会更长,所以尽可能大一点。

2.递归的变量使用问题

    在遍历文件夹时,采用了递归。而在递归函数调用的时候,都会传入一个数组。而数组是临时的变量,当递归进入到另外一层的时候,代码会对上一层的数组进行内存操作,这个有违背递归的思想。递归的每一层最好只依赖本层的参数,而不要依赖上一层的参数。所以,当数组存在最上一层,然后进行内存操作,很容易出现内存使用不当的问题。解决的办法是使用string对象。每一层只依赖和存储本层的内容。当然这个是建议。

    在大量递归的时候,最好少使用局部的数据。这些局部的变量都会压栈存放,放多了,就容易出现栈溢出,然后爆炸了。而我们通过参数传递变量,会比较好。或者需要积累的数据,可以采用全局变量。

3.代码优化问题

    在字符串操作的时候,可以采用string类,可以实现字符串的=赋值和+=字符串拼接,都非常方便。而且,代码中写的字符串操作函数,在VS2017是不推荐的。C++的头文件一般是iostream,而不是写iostream.h。当然,这个跟VS版本有关,推荐使用最新的VS2017。


下面是参考代码:

#include "StdAfx.h"
#include <windows.h>
#include <iostream>
#include <string.h>
using namespace std;
void getAllFiles(const char *dir) {
	//char cFullPath[100];
	string cFullPath;

	WIN32_FIND_DATA data;
	HANDLE hFind;
	cFullPath = dir;
	cFullPath += "*.*";
	//strcat(strcpy(cFullPath, dir), "*.*");
	hFind = FindFirstFile(cFullPath.c_str(), &data);
	do
	{
		char cNewDir[1024] = {0};
		//string cNewDir;
		if ((!strcmp(".", data.cFileName)) || (!strcmp("..", data.cFileName)))
		{
			continue;
		}

		if (data.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
		{
			//cNewDir = dir;
			//cNewDir += data.cFileName;
			//cNewDir += "\\\\";
			//getAllFiles(cNewDir.c_str());//递归

			strcpy(cNewDir, dir);
			strcat(cNewDir, data.cFileName);
			strcat(cNewDir, "\\\\");
			getAllFiles(cNewDir);//递归
		}
		else {
			//cNewDir = dir;
			//cNewDir += data.cFileName;
		    strcpy(cNewDir, dir);
			strcat(cNewDir, data.cFileName);
		}
		cout << cNewDir << endl;
	} while (FindNextFile(hFind, &data));
	FindClose(hFind);
}
int main(int argc, char* argv[])
{

	int DSLength = GetLogicalDriveStrings(0, NULL);
	char* DStr = new char[DSLength];
	GetLogicalDriveStrings(DSLength, (LPTSTR)DStr);
	int DType;
	int si = 0;
	BOOL fResult;
	for (int i = 0; i<DSLength / 4; ++i)
	{
		DType = GetDriveType(DStr + i * 4);
		if (DType != DRIVE_FIXED)
		{
			continue;
		}
		char dir[100] = { DStr[si],'''':'''',''''\0'''' };
		fResult = GetDiskFreeSpaceEx(dir, NULL, NULL, NULL);
		if (!fResult)
		{
			continue;
		}

		strcat(dir, "\\\\");
		getAllFiles(dir);

		si += 4;
	}
	return 0;
}
     再次对耽误一些时间说声抱歉。感谢支持。