Window文件目录遍历 和 WIN32_FIND_DATA 结构(非常详细的中文注释)
第一部分 *百度百科提供的内容总结:WIN32_FIND_DAT
第二部分 *程序实例
第三部分 *一篇使用FindFirstFile和FindNextFile函数的博文
第一部分
1.关于文件的全部属性信息,有以下以下9种:
文件的标题名、文件的属性(只读、存档,隐藏等)、文件的创建时间、文件的最后访问时间、文件的最后修改时间、文件大小的高位双字、文件大小的低位双字、保留、保留。在这里只有文件标题名和文件的长度可以通过CFile类比较方便的获得,而对于其他几种属性的获取和设置就无能为力了。
- typedef struct _WIN32_FIND_DATA
- {
- DWORD dwFileAttributes; //文件属性
- FILETIME ftCreationTime; // 文件创建时间
- FILETIME ftLastAccessTime; // 文件最后一次访问时间
- FILETIME ftLastWriteTime; // 文件最后一次修改时间
- DWORD nFileSizeHigh; // 文件长度高32位
- DWORD nFileSizeLow; // 文件长度低32位
- DWORD dwReserved0; // 系统保留
- DWORD dwReserved1; // 系统保留
- TCHAR cFileName[ MAX_PATH ]; // 长文件名(最多可达 255 个字符的长文件名),带句点和扩展名
- TCHAR cAlternateFileName[ 14 ]; //8.3格式文件名(句点前最多有8个字符,而扩展名最多可以有3个字符)
- } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
可以通过FindFirstFile()函数根据当前的文件存放路径查找该文件来把待操作文件的相关属性读取到WIN32_FIND_DATA结构中去:
- WIN32_FIND_DATA ffd ;
- HANDLE hFind = FindFirstFile("c:\\test.dat",&ffd);
在使用这个结构时不能手工修改这个结构中的任何数据,结构对于开发人员来说只能作为一个只读数据,其所有的成员变量都会由系统完成填写。在MSDN帮助中可以查找到关于WIN32_FIND_DATA结构的更加详细的说明。
2.文件属性信息的获取与更改
为了更好的保存获取到的文件属性信息,对应于文件属性构造一个自定义的FILE_INFO数据结构,获取的属性信息可暂存于此:
- typedef struct _FILE_INFO
- {
- TCHAR szFileTitle[128]; //文件的标题名
- DWORD dwFileAttributes; //文件的属性
- FILETIME ftCreationTime; //文件的创建时间
- FILETIME ftLastAccessTime; //文件的最后访问时间
- FILETIME ftLastWriteTime; //文件的最后修改时间
- DWORD nFileSizeHigh; //文件大小的高位双字
- DWORD nFileSizeLow; //文件大小的低位双字
- DWORD dwReserved0; //保留,为0
- DWORD dwReserved1; //保留,为0
- } FILE_INFO, * PFILE_INFO;
首先用FindFirstFile()函数将文件属性获取到WIN32_FIND_DATA 结构对象FindFileData中去,之后可以用FindClose()将其关闭,并把FindFileData中的有关文件属性信息的内容复制到自定义结构FILE_INFO的结构对象FileInfo中备用。下面是关于这部分描述的部分关键代码:
- //声明结构对象
- FILE_INFO FileInfo;
- WIN32_FIND_DATA FindFileData;
- ……
- //获取文件属性信息
- FindClose(FindFirstFile("Test.txt",&FindFileData));
- memset(&FileInfo,0,sizeof(FILE_INFO));
- ……
- //将文件属性信息保存到FileInfo中备用
- strcpy(FileInfo.szFileTitle,myFile.GetFileTitle());
- FileInfo.dwFileAttributes = FindFileData.dwFileAttributes;
- FileInfo.ftCreationTime = FindFileData.ftCreationTime;
- FileInfo.ftLastAccessTime = FindFileData.ftLastAccessTime;
- FileInfo.ftLastWriteTime = FindFileData.ftLastWriteTime;
- FileInfo.nFileSizeHigh = FindFileData.nFileSizeHigh;
- FileInfo.nFileSizeLow = FindFileData.nFileSizeLow;
- ……
在获取到文件的原始属性信息后既可以原封不动的将属性重新写到文件,也可以对其中某一项或某几项属性内容进行修改后再行写入文件,从而达到更改文件属性的目的。比如可以用SetFileTime()函数设置文件的创建时间、最近一次访问时间以及最近一次修改的时间等等:
- SetFileTime((HANDLE)destFile.m_hFile, //待写入的文件句柄
- &FileInfo.ftCreationTime, //文件的创建时间
- &FileInfo.ftLastAccessTime, //文件最近一次的访问时间
- &FileInfo.ftLastWriteTime); //文件最近一次的修改时间
- 也可以用SetFileAttributes() 函数实现对文件属性的修改:
- SetFileAttributes(FileInfo.szFileTitle,FileInfo.dwFileAttributes);
- BOOL WINAPI MoveFile(LPCSTR Existing, LPCSTR Target);
- MoveFile("D:\\Temp\\a.txt", "E:\\MyPath\\b.txt"); 将D:\Temp\a.txt移动到E:\MyPath并改名为b.txt
- BOOL WINAPI CopyFile(LPCSTR oldFileName, LPCSTR newFileName, BOOL failIfExists);
- oldFileName: 原始文件名;
- newFileName: 目标文件名;
---------------------------------百度百科引用内容结束----------------
第二部分
5. _access(char *); //判断文件或文件夹路径是否合法 <direct.h>
_chdir(char *); //设置当前目录 <direct.h>
6.补充findfirst, findnext 和_findfirst, _findnext搜索磁盘目录
四个函数全部属于 io.h 头文件中
- 1. int findfirst(char *pathname, struct ffblk *ffblk, int attrib);
- 2. int findnext(struct ffblk *ffblk);
程序例1:
- /*用于文件的查找和删除*/
- #include <stdio.h>
- #include <dir.h>
- //两个函数需要定义一个结构体来存储函数返回的数据。结构体如下:
- struct ffblk
- {
- char ff_reserved[21]; /*DOS保留字*/
- char ff_attrib; /*文件属性*/
- int ff_ftime; /*文件时间*/
- int ff_fdate; /*文件日期*/
- long ff_fsize; /*文件长度*/
- char ff_name[13]; /*文件名*/
- }
- //将结构体中的ff_name[13]显示出来即可。
- int main(void)
- {
- struct ffblk ffblk;
- int done;
- printf("Directory listing of *.*\n");
- done = findfirst("*.*",&ffblk,0);
- while (!done)
- {
- printf(" %s\n", ffblk.ff_name);
- done = findnext(&ffblk);
- }
- return 0;
- }
- 3. int _findnext(intptr_t handle,struct _finddata_t *fileinfo); \\搜索与_findfirst函数提供的文件名称匹配的下一个实例,若成功则返回0,否则返回-1
- 4. long _findfirst( char *filespec, struct _finddata_t *fileinfo ); \\搜索与指定的文件名称匹配的第一个实例,若成功则返回第一个实例的句柄,否则返回-1L
- 参数说明:struct _finddata_t的定义见于io.h
- struct _finddata_t
- {
- unsigned attrib;
- time_t time_create; /* -1 for FAT file systems */
- time_t time_access; /* -1 for FAT file systems */
- time_t time_write;
- _fsize_t size;
- char name[260];
- };
- shmiloveyou 补充:sttrib参数有如下类型:
- _A_ARCH(存档)
- _A_HIDDEN(隐藏)
- _A_NORMAL(正常)
- _A_RDONLY(只读)
- _A_SUBDIR(文件夹)
- _A_SYSTEM(系统)
程序例2--遍历指定目录下的文件和文件夹:
- ////shmiloveyou:特别注意,这个实例有个严重的问题,遍历会失败
- ///原作者已经不详,我会在“程序例3中用实例指出问题所在”
- 显示所有的文件:
- #include <io.h>
- #include <iostream>
- #include <string>
- #include <windows.h>
- using namespace std;
- string sRoot = "D:";
- string sSuffix = "\\test\\*.*"; // 后缀 //shmiloveyou:这样写只会查找文件,"\\*"表示匹配所有包括文件夹
- void Move(string sPath);
- void main()
- {
- Move(sRoot);
- system("pause");
- }
- void Move(string sPath)
- {
- struct _finddata_t file;
- long hFile, hFileNext;
- string sPathLast = sPath + sSuffix; // sPathLast = "D:\\test\\*.*"
- hFile = _findfirst(sPathLast.c_str(), &file);
- if(hFile == -1)
- {
- cout<<"文件不存在."<<endl;
- return;
- }
- else
- {
- cout<<file . name<<endl;
- }
- hFileNext = _findnext(hFile, &file); //shmiloveyou:这句多余
- while(_findnext(hFile, &file) == 0)
- { //shmiloveyou:没有过滤掉本级目录'.'和父级目录'..'
- if(file.attrib == _A_SUBDIR)
- {
- string sAddPath = sPath;
- sAddPath += "\\";
- sAddPath += file . name;
- cout<<"目录:"<<sAddPath<<endl;
- Move(sAddPath);
- }
- else
- {
- string sAddPath = sPath;
- sAddPath += "\\";
- sAddPath += file . name;
- cout<<"文件:"<<sAddPath<<endl;
- }
- }
- //shmiloveyou:作者没有关闭文件句柄 _closefile(hFile);
- }
运行结果类似这样,总之是失败的:
总结:
造成这种结果是由于,作者没有考虑“本级目录和父目录”这个概念,因为_findfirst函数最先查找的就是本级目(此时file.name[0] == '.'必成立),而且还会查找父级目录(此时file.name[0]和file.name[1]都等于'.')。这就是为什么上面的图片中会有那么多的‘.’和‘..’。怎么办呢?添加一段程序处理这个问题,只要“ file.name[0] == '.' ”成立就继续while循环。程序如下:
程序例3:(shmiloveyou -- 原创 2014-01-04)
- #include <io.h>
- #include <iostream>
- #include <string>
- #include <windows.h>
- #include <direct.h>
- using namespace std;
- string sRoot = "G:"; //根目录
- string sSuffix = "\\DesignModal"; //中间路径
- string sEnd = "\\"; //路径末尾追加的部分
- void Move(string sPath);
- int main(void)
- {
- string sPath = sRoot + sSuffix; //sPath="G:\\DesignModal"
- Move(sPath);
- system("pasue");
- return 0;
- }
- void Move( string sPath)
- {
- struct _finddata_t file;
- memset(&file, 0, sizeof(file)); //初始化结构
- long hFile;
- string sPathLast = sPath; //sPathLast="G:\\DesignModal"
- if (_chdir(sPathLast.c_str()) != 0) //_chdir函数设置当前目录
- {
- cerr << "当前目录设置失败!" << endl;
- exit(-1);
- }
- hFile = _findfirst("*",&file); //参数1:char *类型,"*"表示通配符,可以查找文件、文件夹
- if(hFile == -1)
- {
- cout << " 遍历失败!" << endl;
- return ;
- }
- do
- {
- if(file.name[0] == '.') //过滤本级目录和父目录 此处就是“程序例2”中的病根所在
- continue;
- if(file.attrib == _A_SUBDIR) //子文件夹
- {
- string sAddPath = sPath;
- sAddPath += "\\";
- sAddPath += file.name;
- cout << "目录:" << sAddPath << endl;
- Move(sAddPath); //递归遍历
- }
- else
- {
- string sAddPath = sPath;
- sAddPath += "\\";
- sAddPath += file.name;
- cout << "文件:" << sAddPath << endl;
- }
- }while(_findnext(hFile,&file) == 0); //没有找到文件或文件夹
- _findclose(hFile); //一定记得关闭文件句柄
- }
运行效果:
第三部分
参考博文:http://blog.csdn.net/dyx1024/article/details/2759413【转】
上面的博文中作者使用FindFirstFile和FindNextFile这两个函数实现指定目录遍历的。
避免参考博文丢失(最初博文地址已经失效),遂引用如下:
- //转自:http://www.vcgood.com/forum_posts.asp?TID=2261&PN=1 地址已经失效
- //用于输出指定目录下的所有文件的文件名,包括子目录。
- 版本1:用string处理,方便,容易理解.
- #include <windows.h>
- #include <iostream>
- #include <string>
- using namespace std;
- bool IsRoot(string Path)
- {
- string Root;
- Root=Path.at(0)+"://";
- if(Root==Path)
- return true;
- else
- return false;
- }
- void FindInAll(string Path)
- {
- string szFind;
- szFind=Path;
- if(!IsRoot(szFind))
- szFind+="//";
- szFind+="*.*";
- WIN32_FIND_DATA FindFileData;
- HANDLE hFind=FindFirstFile(szFind.c_str(),& FindFileData);
- if(hFind==INVALID_HANDLE_VALUE)
- return ;
- do
- {
- if(FindFileData.cFileName[0]=='.') //过滤本级目录和父目录
- continue;
- if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //如果找到的是目录,则进入此目录进行递归
- {
- string szFile;
- if(IsRoot(Path))
- szFile=Path+FindFileData.cFileName;
- else
- szFile=Path+"//"+FindFileData.cFileName;
- FindInAll(szFile);
- }
- else //找到的是文件
- {
- string szFile;
- if(IsRoot(Path))
- szFile=Path+FindFileData.cFileName;
- else
- szFile=Path+"//"+FindFileData.cFileName;
- cout<<szFile<<endl;
- cout<<FindFileData.cFileName<<endl;
- }
- }
- while(FindNextFile(hFind,& FindFileData));
- FindClose(hFind);
- }
- int main()
- {
- FindInAll("D://C++");
- return 0;
- }
- 版本2:编译器的通用性更强
- #include <windows.h>
- #include <iostream>
- using namespace std;
- BOOL IsRoot(LPCTSTR lpszPath)
- {
- TCHAR szRoot[4];
- wsprintf(szRoot,"%c://",lpszPath[0]);
- return (lstrcmp(szRoot,lpszPath)==0);
- }
- void FindInAll(::LPCTSTR lpszPath)
- {
- TCHAR szFind[MAX_PATH];
- lstrcpy(szFind,lpszPath); //windows API 用lstrcpy,不是strcpy
- if(!IsRoot(szFind))
- lstrcat(szFind,"//");
- lstrcat(szFind,"*.*"); //找所有文件
- WIN32_FIND_DATA wfd;
- HANDLE hFind=FindFirstFile(szFind,& wfd);
- if(hFind==INVALID_HANDLE_VALUE) // 如果没有找到或查找失败
- return;
- do
- {
- if(wfd.cFileName[0]=='.')
- continue; //过滤这两个目录
- if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- {
- TCHAR szFile[MAX_PATH];
- if(IsRoot(lpszPath))
- wsprintf(szFile,"%s%s",lpszPath,wfd.cFileName);
- else
- wsprintf(szFile,"%s//%s",lpszPath,wfd.cFileName);
- FindInAll(szFile); //如果找到的是目录,则进入此目录进行递归
- }
- else
- {
- TCHAR szFile[MAX_PATH];
- if(IsRoot(lpszPath))
- wsprintf(szFile,"%s%s",lpszPath,wfd.cFileName);
- else
- wsprintf(szFile,"%s//%s",lpszPath,wfd.cFileName);
- printf("%s/n",szFile); //对文件进行操作
- }
- }
- while(FindNextFile(hFind,&wfd));
- FindClose(hFind); //关闭查找句柄
- }
- int main()
- {
- FindInAll("D://C++");
- return 0;
- }
http://blog.csdn.net/qq2399431200/article/details/11878611
Window文件目录遍历 和 WIN32_FIND_DATA 结构(非常详细的中文注释)的更多相关文章
- STM32 IAP程序 源码 和测试代码 有详细的中文注释
http://bbs.21ic.com/forum.php?mod=viewthread&tid=588265&reltid=624002&pre_pos=2&ext= ...
- Android安全开发之ZIP文件目录遍历
1.ZIP文件目录遍历简介 因为ZIP压缩包文件中允许存在“../”的字符串,攻击者可以利用多个“../”在解压时改变ZIP包中某个文件的存放位置,覆盖掉应用原有的文件.如果被覆盖掉的文件是动态链接s ...
- HighCharts学习笔记(二)HighCharts结构及详细配置
HighCharts结构及详细配置: 一.HighCharts整体结构: 通过查看API文档我们知道HighCharts结构如下:(API文档在文章后面提供下载) var chart = new Hi ...
- Android 安全开发之 ZIP 文件目录遍历
1.ZIP文件目录遍历简介 因为ZIP压缩包文件中允许存在"../"的字符串,攻击者可以利用多个"../"在解压时改变ZIP包中某个文件的存放位置,覆盖掉应用原 ...
- Linux 目录结构及详细操作
目录 Linux 目录结构及详细操作 目录结构 目录结构的特点 目录结构挂载 目录结构发展 关闭selinux(了解) 重要目录说明(etc目录说明) 1.网卡配置文件 2.解析配置文件 3.主机名称 ...
- ❤️这应该是Postman最详细的中文使用教程了❤️(新手使用,简单明了)
️这应该是Postman最详细的中文使用教程了️(新手使用,简单明了) 在前后端分离开发时,后端工作人员完成系统接口开发后,需要与前端人员对接,测试调试接口,验证接口的正确性可用性.而这要求前端开发进 ...
- Linux目录结构及详细介绍
/:根目录,位于Linux文件系统目录结构的顶层,一般根目录下只存放目录,不要存放文件,/etc./bin./dev./lib./sbin应该和根目录放置在一个分区中. /bin,/usr/bin:该 ...
- 【Linux】Linux目录结构及详细介绍
00. 目录 01. 常用目录介绍 /:根目录,位于Linux文件系统目录结构的顶层,一般根目录下只存放目录,不要存放文件,/etc./bin./dev./lib./sbin应该和根目录放置在一个分区 ...
- CentOS目录结构超详细版
最近初学Linux 对linux的目录产生了很多疑问,看到这篇文章,让我顿时对目录有了一个清晰的认识!推荐给大家! ------------------------------------------ ...
随机推荐
- 【t006】三角形分形描绘问题
Time Limit: 1 second Memory Limit: 50 MB [问题描述] 分形是以多种概念和方法相互冲击融合为特征的图形.分形所呈现的无穷玄机和美感引发人们去探索.分形使人们觉悟 ...
- hadoop 3.x 无法访问hdfs(50070,8088)的web界面
1.启动hadoop.然后netstat -nltp|grep 50070,如果,没有找到进程,说明没有配置web界面的端口修改hdfs-site,xml中加上如下配置 再次启动后,netstat - ...
- Java带参数的线程类ParameterizedThread——即如何给Thread传递参数
在Java中似乎没有提供带运行参数的线程实现类,在第三方类库中也没有找到.网上有大量的文章在讨论这个问题,但都没有提供很好的代码封装解决方案,这令我很吃惊.如果读者知道有官方或者第三方的实现方式,欢迎 ...
- Tomcat 学习总结
1. 下载地址 Eclipse: http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/photo ...
- ajax的跨域请求问题:减少options请求
服务器端在Response Headers里添加字段Access-Control-Max-Age: 86400 , "Access-Control-Max-Age"表明在86400 ...
- WPF 使用 SharpDX
原文:WPF 使用 SharpDX 版权声明:博客已迁移到 http://lindexi.gitee.io 欢迎访问.如果当前博客图片看不到,请到 http://lindexi.gitee.io 访问 ...
- [Scikit-Learn] - 数据预处理 - 归一化/标准化/正则化
reference: http://www.cnblogs.com/chaosimple/p/4153167.html 一.标准化(Z-Score),或者去除均值和方差缩放 公式为:(X-mean)/ ...
- 双目相机标定以及立体测距原理及OpenCV实现
单目相机标定的目标是获取相机的内参和外参,内参(1/dx,1/dy,Cx,Cy,f)表征了相机的内部结构参数,外参是相机的旋转矩阵R和平移向量t.内参中dx和dy是相机单个感光单元芯片的长度和宽度,是 ...
- tar.gz文件命名及压缩解压方法
tar.gz文件命名 tar是把文件打成一个包,并不压缩; gz是用gzip把打成包的.tar文件压缩; 所以成了一个.tar.gz的文件 压缩 # tar cvfz backup.tar.gz /x ...
- Oracle实践--PL/SQL综合之分页存储过程
Oracle PL/SQL分页的存储过程 Oracle,分页,存储过程三个词结合起来,来个综合点的小练习,运用之前的PL/SQL创建一个分页的存储过程,仅仅须要简单几步就可以. 1.声明一个引用游标 ...