数据结构课设:【简单文件资源管理器】

需要项目源码的可以私信作者~~~


项目概述

本项目旨在实现一个简单的资源管理器,用于模拟计算机操作系统中文件夹和文件的管理操作。该资源管理器实现基本的录入、修改、删除、输出和查询操作。此外,项目还包含一些扩展功能,如返回、导出、导入、排序等。

工具准备

Visual Studio 社区版 2022
注:需安装MFC扩展包!!!

项目创建

打开VS,新建项目,选择MFC应用以实现图形化界面

在这里插入图片描述

应用程序类型选择基于对话框,使用MFC处选择在静态库中使用MFC后即可创建项目

在这里插入图片描述

项目编写

创建项目完成后,映入眼帘的就是我们的主界面,可以在资源视图–>Dialog中打开

在这里插入图片描述

主界面设计

首先我们完成主界面的图形设计

通过拖拽右侧工具箱的控件Edit ControlButtonList Control

在这里插入图片描述

通过右键控件选择属性修改button描述文字List Control视图

在这里插入图片描述

在这里插入图片描述

这样,我们就完成主界面的图形设计

文件浏览

弹出资源管理器

接着,我们右键List Control选择添加变量,为其命名变量m_FileList

在这里插入图片描述

然后我们回到解决方案资源管理器视图,在项目–>源文件下找到项目名Dlg.cpp的文件,其就是主界面对应的主文件

在这里插入图片描述

OnInitDialog初始化函数下添加以下代码以设计List Control的表头

m_FileList.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);
m_FileList.InsertColumn(0, L"名称", 0, 190);
m_FileList.InsertColumn(1, L"类型", 0, 80);
m_FileList.InsertColumn(2, L"目录", 0, 250);
m_FileList.InsertColumn(3, L"大小", 0, 100);
m_FileList.InsertColumn(4, L"时间", 0, 220);

效果如下:

在这里插入图片描述

然后我们回到主界面,双击Button控件进入点击事件函数的编写,实现弹出资源管理器

// 弹出文件管理器
void CResourcesManagementDlg::OnBnClickedButton1()
{
	UpdateData(TRUE);
	memset(wcPath, 0, MAX_PATH);
	BROWSEINFO bi;
	bi.hwndOwner = m_hWnd;
	bi.pidlRoot = NULL;
	bi.lpszTitle = L"选择目录";
	bi.ulFlags = 0;
	bi.lParam = 0;
	bi.iImage = 0;
	bi.lpfn = NULL;
	bi.pszDisplayName = wcPath;

	LPITEMIDLIST lp = SHBrowseForFolder(&bi);
	SHGetPathFromIDList(lp, wcPath);
	if (!wcscmp(wcPath, L"")) 
	{
		MessageBox(L"选择失败", L"错误", MB_OK);
		return;
	}
	else 
	{
		MessageBox(L"选择成功", L"提示", MB_OK);
		m_DriPath.Format(L"%s", wcPath);
		m_FileList.DeleteAllItems();
		FindDirFile(wcPath);
	}
	UpdateData(FALSE);
}

导入目录

另外的,我们编写FindDirFile函数实现导入目录功能

注:文件夹大小为0

// 导入目录
void CResourcesManagementDlg::FindDirFile(WCHAR* wcDirPath)
{
	WCHAR wcRootPath[1024];
	WCHAR wcSubPath[1024];
	WCHAR wstrFileSize[32];
	WIN32_FIND_DATA wfdFileData = { 0 };
	DWORD dwIndex = 0;
	SYSTEMTIME fileTime;

	wsprintf(wcRootPath, L"%s*.*", wcDirPath);
	HANDLE hFile = FindFirstFile(wcRootPath, &wfdFileData);

	if (hFile != INVALID_HANDLE_VALUE) 
	{
		do {
			memset(wcSubPath, 0, 1024);
			if ('.' == wfdFileData.cFileName[0]) 
			{
				continue;
			}
			wsprintf(wcSubPath, L"%s%s", wcDirPath, wfdFileData.cFileName);
			if (wfdFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 
			{
				m_FileList.InsertItem(dwIndex, wfdFileData.cFileName, dwIndex);
				m_FileList.SetItemText(dwIndex, 1, L"目录");
				m_FileList.SetItemText(dwIndex, 2, wcSubPath);
				m_FileList.SetItemText(dwIndex, 3, L""); // 目录没有大小

				FileTimeToSystemTime(&(wfdFileData.ftLastWriteTime), &fileTime);
				m_FileList.SetItemText(dwIndex, 4, ConvertSystemTimeToWString(fileTime).c_str()); // wfdFileData.ftLastWriteTime
			}
			else 
			{
				m_FileList.InsertItem(dwIndex, wfdFileData.cFileName);
				m_FileList.SetItemText(dwIndex, 1, L"文件");
				m_FileList.SetItemText(dwIndex, 2, wcSubPath);

				// 文件大小  
				ULARGE_INTEGER fileSize;
				fileSize.LowPart = wfdFileData.nFileSizeLow;
				fileSize.HighPart = wfdFileData.nFileSizeHigh;
				_ultot_s(fileSize.QuadPart, wstrFileSize, 10, 10); // 转换为字符串,不包括逗号分隔符  
				m_FileList.SetItemText(dwIndex, 3, wstrFileSize);

				// 文件最后修改时间 
				FileTimeToSystemTime(&(wfdFileData.ftLastWriteTime), &fileTime);
				m_FileList.SetItemText(dwIndex, 4, ConvertSystemTimeToWString(fileTime).c_str());
			}
			dwIndex++;

		} while (FindNextFile(hFile, &wfdFileData));
	}
}

此外我们还要实现辅助函数ConvertSystemTimeToWString实现SystemTime类型转WString类型,帮助查询文件最后修改时间

// SystemTime类型 转 WString类型
std::wstring ConvertSystemTimeToWString(const SYSTEMTIME& st)
{
	// 足够大的缓冲区来存储日期和时间字符串
	wchar_t buffer[128]; 

	// 使用swprintf_s或swprintf来格式化日期和时间   
#ifdef _MSC_VER // 检查是否是Microsoft编译器  
	swprintf_s(buffer, sizeof(buffer) / sizeof(wchar_t), L"%04d-%02d-%02d %02d:%02d:%02d",
		st.wYear, st.wMonth, st.wDay,
		st.wHour, st.wMinute, st.wSecond);

#else  
	swprintf(buffer, sizeof(buffer) / sizeof(wchar_t), L"%04d-%02d-%02d %02d:%02d:%02d",
		st.wYear, st.wMonth, st.wDay,
		st.wHour, st.wMinute, st.wSecond);

#endif  
	// 将C风格的字符串转换为std::wstring  
	return std::wstring(buffer);
}

升降序

需要我们在主菜单中为List Control添加类向导

消息处选择LVN_COLUMNCLICK
在这里插入图片描述

我们对主菜单中新生成的OnColumnclickList1函数进行编写,如下:

// 根据内容升降序
void CResourcesManagementDlg::OnColumnclickList1(NMHDR* pNMHDR, LRESULT* pResult)
{
	// 将NMHDR指针转换为LPNMLISTVIEW指针
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	// 初始化结果变量
	*pResult = 0;

	// 如果当前点击的列ID与上一次点击的列ID不同  
	if (dwSelColID != pNMLV->iSubItem)
	{
		// 更新选中的列ID  
		dwSelColID = pNMLV->iSubItem;
		bASC = bASC;
	}
	else
		// 如果点击的是同一列,则切换升序/降序  
		bASC = !bASC;

	// 获取ListView中的项数  
	int count = m_FileList.GetItemCount();
	// 为List中的每一项设置项数据
	for (int i = 0; i < count; i++)
		m_FileList.SetItemData(i, i);

	// 对List进行排序  
	m_FileList.SortItems(CompareFunc, (LPARAM)(&m_FileList));

	// 初始化结果变量
	*pResult = 0;
}

弹出菜单

回到资源视图,我们可以右键项目,选择添加资源–>Menu,新建菜单

在这里插入图片描述

我们对菜单进行简单设计

在这里插入图片描述

回到主界面,我们选中对话框,右键选择类向导

在消息框选择NM_RCLICK

在这里插入图片描述

完成后,主文件会生成OnRclickList1函数

我们通过以下代码实现弹出菜单功能

// 弹出菜单
void CResourcesManagementDlg::OnRclickList1(NMHDR* pNMHDR, LRESULT* pResult)
{
	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	dwIndexFlag = pNMItemActivate->iItem;
	POINT pt = {};
	GetCursorPos(&pt);
	HMENU hMenu = LoadMenu(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDR_MENU1));
	hMenu = GetSubMenu(hMenu, 0);
	TrackPopupMenu(hMenu, TPM_CENTERALIGN, pt.x, pt.y, 0, m_hWnd, NULL);
	*pResult = 0;
}

我们还需要编写回调函数CompareFunc帮助升降序功能的实现

// 添加回调函数
static int CALLBACK CompareFunc(LPARAM  lParam1, LPARAM   lParam2, LPARAM   lParamSort)
{
	// 将 lParamSort 转换为 CListCtrl 指针,以便后续使用列表控件的方法  
	CListCtrl* pListCtrl = (CListCtrl*)lParamSort;

	// 定义一个 LVFINDINFO 结构体,用于查找列表项  
	LVFINDINFO findInfo;
	findInfo.flags = LVFI_PARAM; // 指示按 lParam 查找  
	findInfo.lParam = lParam1; // 第一个列表项的参数值  
	// 查找 lParam1 对应的列表项索引  
	int iItem1 = pListCtrl->FindItem(&findInfo, -1);

	// 更新 findInfo 的 lParam 为 lParam2,并查找 lParam2 对应的列表项索引  
	findInfo.lParam = lParam2;
	int iItem2 = pListCtrl->FindItem(&findInfo, -1);

	// 获取两个列表项在指定列的文本内容  
	CString strItem1 = pListCtrl->GetItemText(iItem1, dwSelColID);
	CString strItem2 = pListCtrl->GetItemText(iItem2, dwSelColID);
	char* str1 = (char*)strItem1.GetBuffer(strItem1.GetLength());
	char* str2 = (char*)strItem2.GetBuffer(strItem1.GetLength());

	// 根据 bASC 变量的值决定是升序比较还是降序比较  
	if (bASC)
		// 升序比较  
		return strcmp(str1, str2);
	else
		// 降序比较  
		return strcmp(str2, str1);
}

打开目录

回到菜单视图

我们右键刚刚添加的打开目录选择添加事件处理程序类列表这里我们还是选择刚刚的主文件

在这里插入图片描述

之后我们对主文件新生成的函数进行编写,实现打开目录功能

// 打开目录
void CResourcesManagementDlg::On32771()
{
	UpdateData(TRUE);
	
	// 文件路径
	CString csDirPath = m_FileList.GetItemText(dwIndexFlag, 2);
	// 文件类型
	CString csDirType = m_FileList.GetItemText(dwIndexFlag, 1);
	if (csDirType == L"文件") 
	{
		MessageBox(L"该路径不是目录", L"错误", MB_OK);
		return;
	}

	// 拼接路径
	csDirPath = csDirPath + L"\\";
	WCHAR wcDirPath[1024];
	memset(wcDirPath, 0, 1024);
	CStringW strW = CT2CW(csDirPath);
	wcscpy(wcDirPath, strW);

	// 刷新目录
	m_FileList.DeleteAllItems();
	FindDirFile(wcDirPath);

	UpdateData(FALSE);
}

文本模式打开文件

同样的,我们可以菜单视图添加文本模式打开文件行,并添加对应的事件处理程序

// 文本模式打开文件
void CResourcesManagementDlg::On32774()
{
	UpdateData(TRUE);

	// 当前文件类型
	CString csDirType = m_FileList.GetItemText(dwIndexFlag, 1);

	// 提示
	if (csDirType == L"文件")
	{
		CString csFilePath = m_FileList.GetItemText(dwIndexFlag, 2);
		
		// 打开文本文件
		ShellExecute(NULL, L"open", csFilePath, NULL, NULL, SW_SHOWNORMAL);
	}
	else
	{
		MessageBox(L"无法打开目录", L"提示", MB_OK);
	}

	UpdateData(FALSE);
}

刷新列表

我们还可以为添加一个刷新目录功能

// 刷新目录
void CResourcesManagementDlg::On32772()
{
	// 清除并重新填充列表控件  
	m_FileList.DeleteAllItems();

	// 刷新目录
	FindDirFile(wcPath);
}

返回上一级文件夹

我们还可以为程序编写返回上一级文件夹功能

// 返回上一级文件夹
void CResourcesManagementDlg::On32777()
{
	g_DirFilePath = m_FileList.GetItemText(dwIndexFlag, 2);

	// 尝试找到最后一个路径分隔符并删除其后的所有内容  
	int pos = g_DirFilePath.ReverseFind('\\');
	if (pos != -1)
	{
		g_DirFilePath = g_DirFilePath.Left(pos); // 截取到最后一个路径分隔符之前的内容  
	}
	else
	{
		// 处理根目录或无效路径的情况  
		MessageBox(L"已经是根目录或无效路径", L"提示", MB_OK);
		return;
	}

	// 清除并重新填充列表控件  
	m_FileList.DeleteAllItems(); 

	// 刷新目录
	FindDirFile(wcPath);
}

这样,我们就完成了文件浏览板块

文件管理

新建文件

首先我们在资源视图下新建一个Dialog作为新建文件的窗口

效果如下:

在这里插入图片描述

之后,我们为对话框添加CreateFile类,为编辑框添加变量m_FileName

再为Button控件添加创建文件功能,代码如下:

// 新建文件
void CRkCreateFile::OnBnClickedButton1()
{
	UpdateData(TRUE);
	if (m_FileName == L"")
	{
		MessageBox(L"无文件名", L"提示", MB_OK);
		return;
	}
	else 
	{
		CString TempPath;
		TempPath = g_DirFilePath + L"\\" + m_FileName;
		HANDLE hFile = CreateFileW(TempPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
		if (hFile == INVALID_HANDLE_VALUE)
		{
			MessageBox(L"创建失败", L"错误", MB_OK);
			OnOK();
			return;
		}
		else
		{
			MessageBox(L"创建成功", L"成功", MB_OK);
			OnOK();
			return;
		}
	}

	UpdateData(FALSE);
}

回到主文件,我们在导入对应的头文件

#include "CreateFile.h"

然后,我们可以为视图菜单下的新建文件添加事件处理程序

// 新建文件
void CResourcesManagementDlg::On32775()
{
	UpdateData(TRUE);

	// 当前文件路径
	g_DirFilePath = m_DriPath;

	// 新建文件弹出窗口
	CRkCreateFile m_CDlg;
	m_CDlg.DoModal();

	// 清除并重新填充列表控件  
	m_FileList.DeleteAllItems();

	// 刷新目录
	FindDirFile(wcPath);

	UpdateData(FALSE);
}

删除文件

同样的,我们可以在菜单视图下新建删除文件行,并添加事件处理程序,代码如下:

// 删除文件
void CResourcesManagementDlg::On32773()
{
	UpdateData(TRUE);

	// 文件类型
	CString csDirType = m_FileList.GetItemText(dwIndexFlag, 1);
	// 文件路径
	CString csFilePath = m_FileList.GetItemText(dwIndexFlag, 2);

	if(csDirType == L"文件")
	{
		// 删除文件
		BOOL bRet = DeleteFile(csFilePath);
		if (bRet) 
		{
			// 刷新列表
			m_FileList.DeleteAllItems();
			FindDirFile(wcPath);
		}
		else 
		{
			MessageBox(L"删除失败", L"提示", MB_OK);
		}
		return;
	}
	else 
	{
		MessageBox(L"无法删除目录", L"提示", MB_OK);
	}

	UpdateData(FALSE);
}

注:此处删除文件功能做了一些限制,只能删除文件,而不能删除文件夹

这样,我们就完成简单资源管理器的编写


需要项目源码的可以私信作者~~~

  • 21
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值