Windows下新建多级文件夹

  1. 使用system函数调用系统命令"md"

注意:字符串变量的话赋值时要使用双斜杠"\\":

system("md C:\\newfolder\\");

如果需要动态新建目录的话:

char *path = "C:\\newfolder\\";

char swap[255];

sprintf(swap, "md %s", path);

system(swap);

不用判断返回值,系统会自动将错误信息打印到标准输出上.

 

  1. _mkdir()

#include <direct.h>

_mkdir("C:\\newfolder");//新建

_rmdir("C:\\newfolder");//删除

#include<io.h>

_access("C:\\newfolder");//判断文件夹是否存在

缺点是不能一下新建多层文件夹,可以裁剪字符串一级一级创建

如何新建多层目录:

//这里的const是对函数的使用者而言的,其实函数内部修改了该const字符串,但又还原了


	void initPath(const char *path)
	{
		assert(path!= NULL);
	
		// 一层层判断目录是否已存在,不存在就新建
		// 这里的字符串最后一个字符正常情况下是'\'
		// 所以最后可以不用再判断了
		// 之所以说上面一点是因为对_mkdir来说
		// "D:\document"和"D:\document\"没有区别
		char *tmp = (char *)path;
		
		while (*tmp)
		{
			if (*tmp == '\\')
			{
				*tmp = '\0';
				if (_access(path, 0))// 头文件io.h
				{
					if (_mkdir(path))
					{
						#ifdef _DEBUG
						fprintf(stderr, "Failed to create directory %s:%s\n", 
							path, strerror(errno));
						#endif
					}
				}
				*tmp = '\\';
			}
			++tmp;
		}
	}

  1. CreateDirectory()

API也不能新建多层文件夹,而且要打印该函数的出错信息也很复杂.Windows这一套真真的让人恶心.思路是一样的,先一层一层判断文件夹是否存在,如果不存在就新建.判断文件夹是否存在使用GetFileAttributes()函数,如果函数返回-1,说明文件/文件夹不存在;否则如果返回的属性有FILE_ATTRIBUTE_DIRECTORY,说明文件夹已存在.


	void createDirectory(const char *path)
	{
		assert(path!= NULL);
		char *tmp = (char *)path;
		LPVOID lpMsgBuf;
	
		while(*tmp)
		{
			if (*tmp == '\\')
			{
				*tmp = '\0';
				DWORD fileAttr = GetFileAttributes((LPCSTR) path);
				if (fileAttr == 0xFFFFFFFF || !(fileAttr & FILE_ATTRIBUTE_DIRECTORY))
				{
					if (!CreateDirectory((LPCTSTR) path, NULL))
					{
						FormatMessage(
							FORMAT_MESSAGE_ALLOCATE_BUFFER | 
							FORMAT_MESSAGE_FROM_SYSTEM | 
							FORMAT_MESSAGE_IGNORE_INSERTS,
							NULL,
							GetLastError(),
							MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
							(LPTSTR) &lpMsgBuf,
							0,
							NULL 
							);
						MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
					}
				}
				*tmp = '\\';
			}
			++tmp;
		}
		// Free the buffer.
		LocalFree(lpMsgBuf);
	}

关于FormatMessage函数,要多说一点关于Windows API错误(失败)信息的获取.看到网上说《Multitheading Applications inWin32(侯捷译)》书里讲述通过宏MTVERIFY就可以知道调用的Windows API函数错在什么地方:


	/*
	* MtVerify.h
	*
	* Error handling for applications in
	* "Multitheading Applications in Win32"
	*
	* The function PrintError() is marked as __inline so that it can be
	* included from one or more C or C++ files without multiple definition
	* errors. For the examples in this book, this works fine.
	* To use the PrintError() in an application, it should be taken out,
	* placed in its own source file, and the "__inline" declaration removed
	* so the function will be globally available.
	*/
	
	#pragma comment(lib, "USER32")
	
	#include <crtdbg.h>
	#define MTASSERT(a) _ASSERTE(a)
	
	
	#define MTVERIFY(a) if (!(a)) PrintError(#a, __FILE__, __LINE__, GetLastError())
	
	__inline void PrintError(LPSTR linedesc, LPSTR filename, int lineno, DWORD errnum) 
	{
	    LPSTR lpBuffer;
	    char errbuf[256];
	
	#ifdef _WINDOWS
	    char modulename[ MAX_PATH];
	#else // _WINDOWS
	    DWORD numread;
	#endif // _WINDOWS
	    
	    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
	        | FORMAT_MESSAGE_FROM_SYSTEM, 
	        NULL, 
	        errnum, 
	        LANG_NEUTRAL, 
	        (LPTSTR) &lpBuffer, 
	        0, 
	        NULL);
	    
	    wsprintf(errbuf, "\nThe following call failed at line %d in %s:\n\n" 
	        "%s\n\nReason: %s\n", lineno, filename, linedesc, lpBuffer);
	
	#ifdef _WINDOWS
	    GetModuleFileName(NULL, modulename, MAX_PATH);
	    MessageBox(NULL, errbuf, modulename, MB_ICONWARNING | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
	#else 
	    WriteFile(GetStdHandle(STD_ERROR_HANDLE), errbuf, strlen(errbuf), &numread, FALSE);
	    Sleep(3000);
	#endif
	
	    exit(EXIT_FAILURE);
	}

经过本人亲测,可用.那么上面的函数可以改为:


	#include "MtVerify.h"
	void createDirectory(const char *path)
	{
		assert(path != NULL);
		char *tmp = (char *)path;
	
		while(*tmp)
		{
			if (*tmp == '\\')
			{
				*tmp = '\0';
				DWORD fileAttr = GetFileAttributes((LPCSTR) path);
				if (fileAttr == (DWORD) -1 || !(fileAttr & FILE_ATTRIBUTE_DIRECTORY))
				{
					MTVERIFY(CreateDirectory((LPCTSTR) path, NULL));
				}
				*tmp = '\\';
			}
			++tmp;
		}

	}

  1. MakeSureDirectoryPathExists()

这绝对是一个暴力的函数,啥都不说了,直接用:

MTVERIFY(MakeSureDirectoryPathExists(path));

别忘了加上两句:

#include <ImageHlp.h>

#pragma comment(lib, "ImageHlp.lib")

加上一点:该函数强制要求参数字符串以反斜杠'\'结尾,如果不以'\'结尾,最后一层文件夹不会建立.

  1. 最后再说几个判断文件夹是否存在的方法
    1. PathFileExists() 可以判断文件或者文件夹是否存在:

if (PathFileExists(path)) {...}

  1. MFCCFileFind

使用CFileFind的成员函数FindFile(),FindNextFile()IsDirectory().


		void createDirectory(const char *path)
		{
			assert(path != NULL);
			char *tmp = (char *)path;
			CFileFind ff;
			
			// 不能搜索硬盘分区根目录,所以要略过
			// 如果严谨一些可以判断是否已到字符串结尾
			while (*tmp++ != '\\') {}
		
			while (*tmp)
			{
				if (*tmp == '\\')
				{
					*tmp = '\0';
					if (ff.FindFile(path, 0))
					{
						// 必须要调用一次FindNextFile()后才能判断
						// IsDirectory(),不知道为什么
						// 因为同一目录下的文件夹和文件也不能完全重名
						// 所以不用担心会找到多个同名的文件/文件夹
						ff.FindNextFile();
						if (!ff.IsDirectory())
						{
							MTVERIFY(CreateDirectory((LPCTSTR) path, NULL));
						}
					}
					else
					{
						MTVERIFY(CreateDirectory((LPCTSTR) path, NULL));
					}
					*tmp = '\\';
				}
				++tmp;
			}

		}

如果是非MFC应用程序,要加头文件afx.hWindows.h(VC6.0下顺序还不能反了,蛋疼),并设置工程为"Use MFC in a Shared DLL".编译通过.

 

  1. 和上面相似,使用Win32 API FindFirstFile()FindNextFile()


		void createDirectory(const char *path)
		{
			assert(path != NULL);
			char *tmp = (char *)path;
			
			// 不能搜索硬盘分区根目录,所以要略过
			// 如果严谨一些可以判断是否已到字符串结尾
			while (*tmp++ != '\\') {}
			
			WIN32_FIND_DATA wfd;
		
			while (*tmp)
			{
				if (*tmp == '\\')
				{
					*tmp = '\0';
					if (FindFirstFile(path, &wfd) == INVALID_HANDLE_VALUE || 
						!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
					{
						MTVERIFY(CreateDirectory((LPCTSTR) path, NULL));
					}
					*tmp = '\\';
				}
				++tmp;
			}
		}

 上述处理的都是绝对路径(而且是以反斜杠结尾的绝对路径), 如果相对路径的话要稍作修改

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页