目录遍历(建立目录树,记录目录属性)仅适用于小样本

directory.h

#pragma once
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include<tchar.h>
#include<string>
#include<stack>
#include<codecvt>
#include<vector>
#define FILE_NOT_IN_NODE -1
class DirTreeNode
{
public:
int deepth;
std::wstring name;
std::wstring SourcePath;
std::vector<std::wstring> files;
std::vector<std::pair<std::wstring, DirTreeNode*>> dirs; //<目录名,子节点> 编号为先文件后目录
DirTreeNode* parentNode;
DirTreeNode(int deepth = 0, DirTreeNode* parentNode = nullptr)
{
this->deepth = deepth;
this->parentNode = parentNode;

}
int Travel(std::wstring); //搜索节点中的文件的序号 没找到为-1
// std::wstring SourcePath(); //搜寻某个节点的路径,返回该节点的路径
};
class DirTree
{
public:
DirTreeNode* Head;
int maxdeepth; //最大深度
int FileNumber; //目录后所有文件数
int DirNumber; //子目录数
std::wstring pathSearch(std::wstring);
};

DirTree* InitTree(std::wstring);
void DelTree(DirTree* root); //递归删除树维持内存安全
void printTree(DirTree* root); //打印整个树
std::wstring LWtoWString(const LPCWSTR input);
std::wstring StoWString(const std::string input);
std::wstring FindLongestFile(DirTree* root); //查找最长文件

 


#include "directory.h"

//inner__开头的函数为该文件内部函数。
//改进空间 可以改动排序方式。可以先讲文件名按首字母排序后用二分排序从而减轻排序负担
std::wstring inner__MaxFileName(std::vector<std::wstring> vec);
void inner__VecMToStack(std::vector<std::pair<std::wstring, DirTreeNode*>> vec, std::stack<DirTreeNode*>& targetStack);
void printLine(int n, std::wstring line);

int DirTreeNode::Travel(std::wstring input)
{
int index = 0;
for (auto &name : this->files)
{
if (name == input)
{
return index;
}
else
{
index++;
}
}
for (auto &temp : this->dirs)
{
if (temp.first == input)
{
return index;
}
else
index++;
}
return FILE_NOT_IN_NODE;

}

//将节点Dirs中的目录所在节点压栈
void inner__VecMToStack(std::vector<std::pair<std::wstring, DirTreeNode*>> vec, std::stack<DirTreeNode*>& targetStack)
{
for (auto p = vec.rbegin(); p != vec.rend(); p++)
{
targetStack.push(p->second);
}
return;
}

std::wstring DirTree::pathSearch(std::wstring input) //查找input文件的路径
{
DirTreeNode* pNode = this->Head;
//遍历查找
int index = 0;
std::wstring path; //返回的文件路径
std::stack<DirTreeNode*> Dirstack;
Dirstack.push(this->Head);
for (int i = 1; i < this->maxdeepth;)
{
pNode = Dirstack.top();
Dirstack.pop();
index = pNode->Travel(input);
if (index != FILE_NOT_IN_NODE)
{
if (pNode->files.size() > index) //目标为普通文件
{
path = pNode->SourcePath + (pNode->files)[index];
}
else
{
index = index - pNode->files.size();
path = pNode->SourcePath + pNode->dirs[index].first;
}
return path;
}
else
{
inner__VecMToStack(pNode->dirs, Dirstack);
}
}
path.append(L"no found");
return path;
}


std::wstring StoWString(const std::string input)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
return converter.from_bytes(input);
}

std::wstring LWtoWString(const LPCWSTR input)
{
std::wstring temp(input);
return temp;
}

LPCWSTR WStoLPC(std::wstring &input)
{
return LPCWSTR(input.c_str());
}

//初始化树
DirTree* InitTree(std::wstring path)
{

std::wstring target,endpath = L"\\*";
int pos = 0;
pos = path.find_last_of(L"\\/");


int deepth = 1; //当前目录深度
int FileNumber = 0; //所有文件数
int DirNumber = 0; //子目录数
DirTree* root = new DirTree;
DirTreeNode* head = new DirTreeNode;
head->name = path.substr(pos + 1);
head->SourcePath = path.substr(0, pos);
root->Head = head;
std::stack<DirTreeNode*> dirstack;
dirstack.push(head);

LPCWSTR Current_Dir; //当前遍历的目录名
WIN32_FIND_DATA file; //记录当前操作的文件或目录的信息
HANDLE h; //当前操作文件的句柄
DirTreeNode* pNode = head; //当前操作的节点指针

DirTreeNode* ChildNode; //子节点指针
std::wstring interval(L"\\");
while (!dirstack.empty())
{
pNode = dirstack.top();
dirstack.pop();
target = pNode->SourcePath + interval + pNode->name + endpath;
Current_Dir = WStoLPC(target);
h = FindFirstFile(Current_Dir, &file);
//遍历该目录中所有文件
do
{
if (!wcscmp(file.cFileName,L".") || !wcscmp(file.cFileName, L".."))
{
continue;
}
else if (file.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) //该文件是目录
{
ChildNode = new DirTreeNode;
ChildNode->parentNode = pNode;
ChildNode->SourcePath = pNode->SourcePath+interval+pNode->name;
ChildNode->deepth = ChildNode->parentNode->deepth + 1;
ChildNode->name = LWtoWString(file.cFileName);
pNode->dirs.push_back({ ChildNode->name, ChildNode });
DirNumber++;
dirstack.push(ChildNode);
}
else if (file.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) //该文件为普通文件
{
pNode->files.push_back(LWtoWString(file.cFileName));
FileNumber++;
}

} while (FindNextFile(h, &file));
deepth = pNode->deepth;
if (!(pNode->files.empty()))
deepth++;
if(deepth > root->maxdeepth)
root->maxdeepth = deepth;
}

root->DirNumber = DirNumber;
root->FileNumber = FileNumber;
return root;
}

//寻找最长的文件路径
//用指针传递代替拷贝,减少内存使用量
std::wstring FindLongestFile(DirTree* root)
{
std::wstring target(L""), temp_FileName;
std::wstring interval(L"\\");
int longestSize = 0;
int temp_Size = 0;
DirTreeNode* pNode = nullptr;
std::stack<DirTreeNode*> DirStack;
DirStack.push(root->Head);
do
{
pNode = DirStack.top();
DirStack.pop();
if (!(pNode->dirs).empty())
{
inner__VecMToStack(pNode->dirs, DirStack);
}
temp_FileName = inner__MaxFileName(pNode->files);
temp_Size = temp_FileName.size() + pNode->SourcePath.size() + pNode->name.size() + 2;
if (temp_Size > longestSize )
{
target = pNode->SourcePath + interval + pNode->name + interval + temp_FileName;
longestSize = target.size();
}

} while (!DirStack.empty());
return target;
}


//iter和pointer的区别
//在files中找寻最大长度的文件
//用指针传递代替拷贝,减少内存使用量
std::wstring inner__MaxFileName(std::vector<std::wstring> vec)
{
std::wstring *target = nullptr;
if (vec.empty())
{
return L"";
}
std::wstring* p = &(vec[0]);
for (int i = 0; i < vec.size();i++)
{
if (target->size() < p->size())
{
target = p;
}
else if (target->size() == p->size() && (*target) < (*p))
{
target = p;
}
}
std::wstring RetWstr(target->c_str());
return RetWstr;
}

void DelTree(DirTree* root)
{
DirTreeNode* pNode;
std::stack<DirTreeNode*> DirStack;
DirStack.push(root->Head);
if (root->Head->dirs.empty())
{
delete root;
return;
}
do
{
pNode = DirStack.top();
DirStack.pop();
inner__VecMToStack(pNode->dirs, DirStack);
delete(pNode);
} while (!pNode->dirs.empty());
delete(root);
return;
}


//打印整个树。
//考虑后面模拟操作
void printTree(DirTree* root)
{
std::stack<DirTreeNode*> DirStack;
std::wstring targetLine;
std::wstring line(L"| "), row(L"-");
DirTreeNode* pNode = nullptr;
DirStack.push(root->Head);
do
{
pNode = DirStack.top();
DirStack.pop();
if (!pNode->dirs.empty())
inner__VecMToStack(pNode->dirs, DirStack);
printLine(pNode->deepth,line);
wprintf(row.c_str());
wprintf(pNode->name.c_str());
putwchar(L'\n');
for (auto& filename : pNode->files)
{
printLine(pNode->deepth + 1, line);
wprintf(row.c_str());
wprintf(filename.c_str());
putwchar(L'\n');
}
} while (!DirStack.empty());
return;
}
void printLine(int n,std::wstring line)
{
for (int i = 0; i < n; i++)
{
wprintf(line.c_str());
}
}

 

#include"directory.h"

int wmain(int argc, TCHAR* argv[])
{
std::wstring path = L"C:\\windows";
DirTree *root;
root = InitTree(path);
printTree(root);
wprintf(L"Number of subdirectories:%d\n",root->DirNumber);
wprintf(L"Number of documents:%d\n",root->FileNumber);
wprintf(L"Deepth:%d\n",root->maxdeepth);
system("pause");
DelTree(root);
}

posted @   fakeeyes  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示