文件路径的保存且进行增删改查操作

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.存储文件的树且进行操作的实现

  • 定义存储的路径的树的结构
    typedef struct BNode 
    	BNode* sub[NUM + 1];
    	int numb;
    	string str = "";
    BNode;
  • 创建一个节点
    BNode* getnode(string str) 
    	
    	BNode* root = new BNode[sizeof(BNode)];
    	if (root == NULL)
    		assert(0);
    	
    	for(int i = 0; i< NUM;i++)
    		root->sub[i] = NULL;
    	
    	root->numb = 0;
    	root->str = str;
    	return root;
    

  • 创建初始的树(这个树是由初始遍历得到的路径构建的)
    //根据文件进行新建
    BNode* create_file(string path, int num) 
    	struct _finddata_t filei;
    	string cur_path = path + "/*.*";
    	int handle = _findfirst(cur_path.c_str(), &filei);
    	BNode* root = NULL;//定义根节点
    	root = getnode(path.substr(path.rfind("/") + 1));
    	if (handle == -1)//返回-1则查找失败
    	
    		cout << "创建失败,因为此时只有根目录" << endl;
    		return NULL;
    	
    	do 
    		if (filei.attrib == _A_SUBDIR) //判断是否是文件夹
    			//此时需要排除两种情况,当前目录,上级目录与此时的文件名称是否相同
    			if ((strcmp(filei.name, "..") != 0) && (strcmp(filei.name, ".") != 0)) 
    				//在这里查询,相当于找到了要存到B_tree的路径的目录的非叶子节点
    				// 因此我们先进行节点的创建与保存
    				//如果是文件夹,且进行递归的话,此时要对num进行清零
    				root->sub[root->numb++] = create_file(path + '/' + filei.name, root->numb);
    			
    			else if ((strcmp(filei.name, "..") == 0) || (strcmp(filei.name, ".") == 0)) 
    				continue;
    			
    			else 
    				root->sub[root->numb] = getnode(filei.name);
    				root->numb++;
    			
    		
    		else 
    			//此时遍历到了叶子节点,那么将叶子节点的值存入当中
    			root->sub[root->numb] = getnode(filei.name);
    			root->numb++;
    		
    
    	 while (!(_findnext(handle, &filei)));//判断此曾是否遍历完成
    	return root;
    
  • 路径的增加
    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

在这里遇到的问题是因为这里new无法完成内存请求,此时抛出bad_alloc来表示分配异常。

前几天遇到的一个问题,然后自己慢慢整出来的,而且代码上感觉有好多繁琐的地方,如果有时间会优化一下,如果有什么逻辑上的错误,还请多多指教。

以上是关于文件路径的保存且进行增删改查操作的主要内容,如果未能解决你的问题,请参考以下文章

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

TP框架中 数据库的增删改查

Linq To Xml操作XML增删改查

xml解析——增删改查操作后将其修改结果保存

c语言 通讯录系统 增删改查 排序 动态内存开辟及文件保存与读取

c语言 通讯录系统 增删改查 排序 动态内存开辟及文件保存与读取