文件路径的保存且进行增删改查操作--利用树进行实现,是将每个文件或文件夹保存到一个节点,然后用树形结构结构进行存储,但是存在一些问题。
Posted 水澹澹兮生烟.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文件路径的保存且进行增删改查操作--利用树进行实现,是将每个文件或文件夹保存到一个节点,然后用树形结构结构进行存储,但是存在一些问题。相关的知识,希望对你有一定的参考价值。
1.要在这里掌握的一些知识
- _finddata_t 结构体是用来存储结文件结构信息的结构体
struct _finddata_t unsigned attrib;//文件属性的存储位置,他存储一个unsigned单元,用于表示文件的属性 time_t time_creat; time_t time_write; time_t time_access; _fsize_t size; char name[_MAX_FNAME]; ; //常使用的三个函数 long _findfirst(char *filespec, struct _finddata_t *fileinfo); /************************************************************ 返回值:如果查找成功的话,将返回一个long型的唯一的查找用的句柄。这个句柄将会在_findnext函数中被使用。失败返回-1. 参数: filespec:标明文件的字符串,可支持通配符。比如:*.c,则表示当前文件夹下的所有后缀为C的文件。 fileinfo :这里就是用来存放文件信息的结构体的指针。这个结构体必须在调用此函数前声明,不过不用初始化,只要分配了内存空间就可以了。函数成功后,函数会把找到的文件的信息放入这个结构体所分配的内存空间中。 ************************************************************/ int _findnext(long handle, struct _finddata_t *fileinfo); /************************************************************ 返回值:若成功返回0,否则返回-1。 参数: handle:即由_findfirst函数返回回来的句柄。 fileinfo:文件信息结构体的指针。找到文件后,函数将该文件信息放入此结构体中。 ************************************************************/ int _findclose(long handle); /************************************************************ 返回值:若成功返回0,否则返回-1。 参数: handle:即由_findfirst函数返回回来的句柄。 ************************************************************/
attrib:文件属性的存储位置,他存储一个unsigned单元,用于表示文件的属性
time_creat:用来记录文件的创建时间
time_write:记录文件最后一次修改时间
time_access:记录文件最后一次访问时间
size:文件的大小
name[_MAX_FNAME]:文件的文件名
2.存储文件的树且进行操作的实现
在这里我进行路径的查找时使用的时win的API,我觉得这个查找出来的更加准确。
- 定义存储的路径的节点的结构
#pragma #include<iostream> #include<string> #include<windows.h> using namespace std; #define MAX_FILEPATH 10000 struct BNode //构建的节点 string file_name; int num; BNode* sub[MAX_FILEPATH]; BNode(string path) : num(0), file_name(path) for (int i = 0; i < MAX_FILEPATH; i++) sub[i] = NULL; ;
- 创建初始的树(这个树是由初始遍历得到的路径构建的)
#include "bt_path.h" BNode* creat_tree(string path, int* count) string path_i = path + "\\\\*.*"; WIN32_FIND_DATA pNextInfo;//保存文件信息 HANDLE hFile = 0; hFile = FindFirstFile(path_i.c_str(), &pNextInfo); BNode* root = NULL; root = new BNode(path.substr(path.rfind("/") + 1)); if (hFile) do if (pNextInfo.cFileName[0] == '.' || pNextInfo.cFileName[0] == '..')//过滤.和.. continue; else //dwFileAttributes值是可以一位或多位的,不好直接使用"=="来判断 if (pNextInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)//判断是否为文件夹 //将文件夹追加到目录,成为下一级要搜索目录 path_i = path + "\\\\" + pNextInfo.cFileName; root->sub[root->num++] = creat_tree(path_i, count);//递归 else //此时为叶子节点,创建并进行输出 (*count)++; root->sub[root->num++] = new BNode(pNextInfo.cFileName); cout << path << "\\\\" << pNextInfo.cFileName << endl; while (FindNextFile(hFile, &pNextInfo));//遍历文件 FindClose(hFile); return 0;
- 路径的增加
void add_file(BNode** root,string path, string add_path) //path是用来与取add_path中的每个文件名称的 //在增加路径的过程中,有可能会增加多个节点 BNode* cur = *(root); path = add_path.substr(0, add_path.find("/"));//从0号位置截到第一个"/"位置 add_path.erase(0, add_path.find("/")+1);//从0号位置向后删除add_path.find("/")个位置 if (cur == NULL) //当没有根目录的时候 cur = getnode(path);//创建根节点 return; else //当有根目录时,且此时根目录相同 path = add_path.substr(0, add_path.find("/"));//从0号位置截到第一个"/"位置 add_path.erase(0, add_path.find("/") + 1);//从0号位置向后删除add_path.find("/")个位置 for (int i = 0; i < cur->numb; i++) if (!strcmp(path.c_str(), (cur->sub[i])->str.c_str())) path = add_path.substr(0, add_path.find("/"));//从0号位置截到第一个"/"位置 add_path.erase(0, add_path.find("/") + 1);//从0号位置向后删除add_path.find("/")个位置 //此时,如果相同,那么继续向下进行查找 cur = cur->sub[i]; else if (cur->numb == i + 1) //此时,说明将cur的子目录遍历完且没有相同的目录,那么此时直接跳出循环 break; while (path != "") BNode* next_node = cur;//在定义一个节点,用来时节点可以向前 //当没有将所有文件插入完,继续插入节点 cur->sub[cur->numb] = getnode(path); cur->numb++; cur = cur->sub[cur->numb]; path = add_path.substr(0, add_path.find("/"));//从0号位置截到第一个"/"位置 add_path.erase(0, add_path.find("/"));//从0号位置向后删除add_path.find("/")个位置 return ;
- 路径的删除
//删除节点,遍历查询,直接删除 void del_file(BNode** root, int* num, string path, string del_path) BNode* cur = *root; if (cur == NULL) return; else //此时遍历查询,并进行比较 path = path + cur->str + "/"; //没有查找到,那么继续向下递归查询 if (strcmp(path.c_str(), del_path.c_str()) == 0) (*num)--; //当查询到有路径是相同时,则删除掉此路径下的所有文件,将这个节点下的所有数据都删除,置空 (*root)->numb = 0; *root = NULL; cout << "此时删除此路径下的所有文件成功" << endl; return; for (int i = 0; i < cur->numb; i++) del_file(&(cur->sub[i]), &(cur->numb), path, del_path); return;
- 路径的遍历查询
void find_path(BNode* root,string path) //递归遍历输出 if (root) //如果root->不为空,那么进行遍历 path = path + root->str + "/"; cout << path << endl; for (int i = 0; i < root->numb; i++) find_path(root->sub[i],path);
- 最后实现的截图
3.遇到的问题
读取访问权限发生冲突:一般情况下两种情况会发生这样的问题。
- 数组访问越界一般是读取位置超过此时数组的长度,当遇到读取访问冲突的提示时,如果异常发生在数组中数据的时候,可优先考虑这种情况发生。
- 空指针异常:主要发生在通过一个指针去读取数据时。一般原因是没有初始化指针时使其成为一个空指针,指向一个不确定的值,随后进行操作。
**在指针未初始化时还会出现其他错误提示:
- 读取访问权限异常
- 0XCCCCCCCC
- 0XCDCDCDCD
在这里遇到的问题还没解决:在对C盘进行遍历的时候(统计了一下,大概文件与文件夹大概20多万个,遍历一半的话是没有问题的)发生了new抛出异常bad_alloc,原因是内存分配不足,有哪个大佬可以帮我看着改一下啊,蟹蟹了。
这里的问题比较多,当遍历一个文件夹下面文件多于100后会出现内存不够的现象,到现在还没有解决,如果有大佬知道为什么,麻烦您帮我这个菜鸡指出。
以上是关于文件路径的保存且进行增删改查操作--利用树进行实现,是将每个文件或文件夹保存到一个节点,然后用树形结构结构进行存储,但是存在一些问题。的主要内容,如果未能解决你的问题,请参考以下文章
c语言 通讯录系统 增删改查 排序 动态内存开辟及文件保存与读取