文件路径的保存且进行增删改查操作--利用树进行实现,是将每个文件或文件夹保存到一个节点,然后用树形结构结构进行存储,但是存在一些问题。

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.遇到的问题

  读取访问权限发生冲突:一般情况下两种情况会发生这样的问题。

  • 数组访问越界一般是读取位置超过此时数组的长度,当遇到读取访问冲突的提示时,如果异常发生在数组中数据的时候,可优先考虑这种情况发生。
  • 空指针异常:主要发生在通过一个指针去读取数据时。一般原因是没有初始化指针时使其成为一个空指针,指向一个不确定的值,随后进行操作。

**在指针未初始化时还会出现其他错误提示:

  1. 读取访问权限异常
  2. 0XCCCCCCCC
  3. 0XCDCDCDCD

在这里遇到的问题还没解决:在对C盘进行遍历的时候(统计了一下,大概文件与文件夹大概20多万个,遍历一半的话是没有问题的)发生了new抛出异常bad_alloc,原因是内存分配不足,有哪个大佬可以帮我看着改一下啊,蟹蟹了。

这里的问题比较多,当遍历一个文件夹下面文件多于100后会出现内存不够的现象,到现在还没有解决,如果有大佬知道为什么,麻烦您帮我这个菜鸡指出。

在这里顺便指路我的最终实现的方法,将遍历得到的文件路径存到map中,将其文件路径设置为key,MD5值为value。icon-default.png?t=M276https://blog.csdn.net/qq_43287694/article/details/123873713

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将TextBox和AdvTree进行链接,可以使用AdvTree控件的AfterNodeSelect事件。在该事件中,可以通过选中节点的Tag属性获取节点对应的数据,并将数据填充到TextBox中。 下面是一个简单的示例代码: ``` private void advTree1_AfterNodeSelect(object sender, AdvTreeNodeEventArgs e) { // 获取选中节点的数据 var data = e.Node.Tag as MyData; // 将数据填充到TextBox中 textBox1.Text = data.Name; textBox2.Text = data.Age.ToString(); textBox3.Text = data.Email; } ``` 对于AdvTree中数据的增删保存操作,可以使用以下代码: ``` // 添加数据 private void AddData(MyData data) { // 创建一个新节点 var newNode = new AdvTreeNode(); newNode.Text = data.Name; newNode.Tag = data; // 将节点添加到AdvTree中 advTree1.Nodes.Add(newNode); } // 删除数据 private void DeleteData(AdvTreeNode node) { // 从AdvTree中移除节点 advTree1.Nodes.Remove(node); } // 修数据 private void UpdateData(AdvTreeNode node, MyData newData) { // 更新节点的Tag属性 node.Tag = newData; // 更新节点的文本 node.Text = newData.Name; } // 找数据 private AdvTreeNode FindNode(MyData data) { // 遍历AdvTree中的节点找与数据对应的节点 foreach (AdvTreeNode node in advTree1.Nodes) { var nodeData = node.Tag as MyData; if (nodeData != null && nodeData.Equals(data)) { return node; } } return null; } // 保存数据 private void SaveData() { // 遍历AdvTree中的节点,将每个节点的数据保存文件中 foreach (AdvTreeNode node in advTree1.Nodes) { var data = node.Tag as MyData; if (data != null) { // 将数据保存文件中 SaveToFile(data); } } } ``` 其中,MyData是自定义的数据类型,可以根据实际需要进行调整。SaveToFile方法是将数据保存文件中的代码,也可以根据实际需要进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值