手搓文件管理系统(持续开发中)

upd:2025/10

  • 初步完成了虚拟的文件夹及文件目录管理,主要功能有:创建虚拟文件夹、显示路径、创建文件、列出当前路径下文件(夹)、转到特定目录。

upd:2025/11/19

  • 初步实现了与 \(\operatorname {windows}\) 的真实接口,现在可以真实地在该 \(\operatorname {exe}\) 下创建文件夹与文件。

upd:2025/11/20

  • 我们实现了编辑文件和保存并退出。现存问题为:编辑文本的时候,文本量小时闪屏问题不严重,文本量超过1000后闪屏问题较为严重(模拟高频率输入时,若写小说等还好)。

upd:2025/11/21

  • 新增登录系统。

upd:2025/11/24

  • 准备了一个 \(\operatorname {4K}\) 小游戏,准备明天加入这个系统里面供游玩 ^_^。

upd:2025/11/25

  • 小游戏已经就位,现在可以使用,耶耶耶。
#include<bits/stdc++.h>
#include<windows.h>
using namespace std;
 
/**
 * command:
 * 			cd [dirname]
 * 				to shift to a name_given dir
 * 			mkdir [dirname]
 * 				create a new dir under current dir
 *				(&md)
 *			touch [filename] 
 *				create a new file under current file
 *				(&touhc)
 * 			ls dir
 * 				list the dir under current dir in specific order
 *				(&ld)
 *			ls file
 *				list the file under current dir
 *				(&lf)
 * 			shut
 *				shut to have a good day without IT productions
 *			ret
 *				directly return to the Desktop
 *				don't ask me why i develop this command
 *				just because IIII HATEEEE inputing "Desktop"!!!!!
 *			cls 
 *				just run system("cls") and then
  *			edit 
 *				key in a filename to edit it
 *				press Alt+F to quit
 *			game
 *				to play game
 *				using F,G,H,J,and O+K to quit
 * */
 
//-----------------文本编辑模块全局变量--------------
string EXE_DIR;
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD originalConsoleMode; //save original console mode
CONSOLE_CURSOR_INFO originalCursorInfo;
//--------------------------------------------------- 
 
 
// ---------------------- 获取exe运行目录 ------------------
string getExeDir() {
    char exePath[MAX_PATH];
    // 获取exe完整路径(比如 D:\project\file_manager.exe)
    GetModuleFileNameA(NULL, exePath, MAX_PATH);
    // 找到最后一个反斜杠,截取目录部分(比如 D:\project)
    string path(exePath);
    size_t pos = path.find_last_of("\\/");
    if (pos != string::npos) {
        path = path.substr(0, pos);
    }
    return path;
}
// ---------------------------------------------------------
 
int dircnt=1;       	 //the number of dir
 
int now=1;          	 //the dir's ID which you are now
int fa[100010];     	 //fa for Union-Find
 
map<string,int>mp;  	 //give it a name turned out an ID
 
 
struct directory{
	string dirname; 	 //its name
	int dep;        	 //the dep in the dir_tree
	vector<int>son; 	 //its son_dir
						 //give it a name turned out an ID of file
	map<string,int>mp_file;  
						 //its son_file
	vector<string>son_file; 
	int filecnt=0;       //the number of file   
}; 
directory a[100010];     //struct for dirs
 
struct file{
	string filename;
};
file b[100010];			 //struct for file
int tfc=0;				 //overall file count
						 //for overall file conduction
map<pair<int,string> ,int>tmf;
 
deque<int>pos;      	 // your current path
int pos_size=1;     	 // the size of path
 
//-----------------辅助函数:构建真实文件路径--------
string buildRealPath() {
    deque<int> temp_pos = pos;
    string real_path = EXE_DIR; // 基于exe运行目录
 
    // 跳过虚拟根目录“Desktop”(因为它对应exe目录,无需拼接)
    temp_pos.pop_front(); // 移除虚拟根的Desktop(pos队列第一个元素是Desktop的ID)
 
    // 拼接后续虚拟目录(比如虚拟路径Desktop/dir1 → 真实路径exe_dir/dir1)
    while (!temp_pos.empty()) {
        int dir_id = temp_pos.front();
        temp_pos.pop_front();
        real_path += "\\"; // Windows路径用反斜杠
        real_path += a[dir_id].dirname;
    }
 
    return real_path;
}
 
static void SetPos(int x,int y){
	COORD point={x,y};
	HANDLE HOutput= GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(HOutput,point);
}
//upd:2025/11/19
//--------------------------------------------------- 
 
//------------------控制台控制函数-------------------
//保存控制台原始配置(编辑前调用) 
void saveConsoleConfig() {
    GetConsoleMode(hStdin, &originalConsoleMode); // 保存控制台模式
    GetConsoleCursorInfo(hStdout, &originalCursorInfo); // 新增:保存默认光标状态
}
 
//设置为编辑模式(无回显无行缓冲) 
void setEditMode(){
	DWORD editMode = originalConsoleMode;
    editMode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT); // 关闭行缓冲和回显
    editMode |= ENABLE_PROCESSED_INPUT | ENABLE_EXTENDED_FLAGS; // 支持方向键
    editMode &= ~ENABLE_QUICK_EDIT_MODE; // 新增:禁用快速编辑模式(减少花屏)
    SetConsoleMode(hStdin, editMode);
    SetConsoleOutputCP(936);
    SetConsoleCP(936);
}
 
// 设置光标可见性(编辑时显示,退出时恢复)
void setCursorVisibility(bool visible) {
    CONSOLE_CURSOR_INFO cursorInfo;
    GetConsoleCursorInfo(hStdout, &cursorInfo); // 获取当前光标信息
    if (visible) {
//        cursorInfo.bVisible = TRUE;  // 光标可见
        cursorInfo.dwSize = 10;       // 光标大小(1-100,20是适中大小)
    } else {
        cursorInfo.bVisible = originalCursorInfo.bVisible; // 恢复默认可见性
        cursorInfo.dwSize = originalCursorInfo.dwSize;       // 恢复默认大小
    }
    SetConsoleCursorInfo(hStdout, &cursorInfo); // 应用设置
}
 
//回复控制台原始模式(编辑后调用,不影响原有系统)
void restoreConsoleConfig(){
	SetConsoleMode(hStdin,originalConsoleMode);
	SetConsoleOutputCP(CP_ACP);
	SetConsoleCP(CP_ACP);
} 
 
//设置光标位置
void clearScreen(){
	CONSOLE_SCREEN_BUFFER_INFO csbi;
    GetConsoleScreenBufferInfo(hStdout, &csbi);
    DWORD dwSize = csbi.dwSize.X * csbi.dwSize.Y;
    DWORD dwWritten;
 
    // 1. 填充空格覆盖屏幕(清除文字)
//    system("cls");
	FillConsoleOutputCharacter(hStdout, ' ', dwSize, {0, 0}, &dwWritten);
	
    // 2. 强制设置文本属性为「黑底白字」(修复花屏)
    // 0x07 是 Windows 控制台默认属性:FOREGROUND_WHITE | BACKGROUND_BLACK
    FillConsoleOutputAttribute(hStdout, 0x07, dwSize, {0, 0}, &dwWritten);
 
//    SetCursorPos(0, 0);
} 
//upd:2025/11/19
//--------------------------------------------------- 
 
//-----------------文件读写函数----------------------
bool readFile(const string &real_file_path ,vector<string>&lines){
	ifstream file(real_file_path,ios::in);
	if(!file.is_open())return false;
	
	lines.clear();
	string line;
	while(getline(file,line)){
		lines.push_back(line);
	}
	file.close();
	if(lines.empty())lines.emplace_back("");
	return true;
}
 
bool saveFile(const string &real_file_path,const vector<string>&lines){
	ofstream file_for_now(real_file_path,ios::out | ios::trunc);
	if(!file_for_now.is_open())return false;
	for(size_t i=0;i<lines.size();i++){
		file_for_now<<lines[i];
		if(i!=lines.size()-1){
			file_for_now<<endl;
		}
	}
	file_for_now.close();
	return true;
}
//upd:2025/11/19
//--------------------------------------------------- 
 
//-----------------文本显示和编辑函数----------------
void displayText(const vector<string>&lines){
	clearScreen();
	SetPos(0,0);
	int lineCount=lines.size();
	for(int i=0;i<lineCount;i++){
		cout<<lines[i];
		if(i!=lineCount-1){
			cout<<'\n';
		}
	}
	cout.flush();
//	for(const auto&line:lines){
//		cout<<line<<endl;
//	}
}
//upd:2025/11/20
 
bool editTextCore(const string &real_file_path){
	vector<string>lines;
	if(!readFile(real_file_path,lines)){
		cout<<"Sorry for failing to get the file!"<<endl;
		system("pause > nul");
		return false; 
	}
	int cursorX=0;
	int cursorY=0;
	cursorY=min(cursorY,static_cast<int>(lines.size())-1);
	bool isEditing=true;
	bool saveSuccess=false;
	
	saveConsoleConfig();
	setEditMode();
	setCursorVisibility(true);
	displayText(lines);
	SetCursorPos(cursorX,cursorY);
	
	INPUT_RECORD inputRecord;
	DWORD readCount;
	
	while(isEditing){
		ReadConsoleInput(hStdin,&inputRecord,1,&readCount);
		if(inputRecord.EventType != KEY_EVENT || !inputRecord.Event.KeyEvent.bKeyDown){
			continue;
		}
		KEY_EVENT_RECORD key=inputRecord.Event.KeyEvent;
		
		//Alt+F save and quit
		if((key.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) and key.wVirtualKeyCode == 0x46){
			saveSuccess = saveFile(real_file_path,lines);
			SetCursorPos(0,static_cast<int>(lines.size()+1));
			clearScreen();
			SetPos(0,0);
			cout<<(saveSuccess?" [ Edit Success ] Successfully saved the file!":" [ Edit Fail ] Failed to save the file!")<<endl;
			isEditing = false;
			break;
		}
		switch(key.wVirtualKeyCode){
			case VK_LEFT:  // 左箭头
				if(cursorX > 0)cursorX--;
				break;
			case VK_RIGHT: // 右箭头
				if(cursorX<static_cast<int>(lines[cursorY].size()))cursorX++;
				break;
			case VK_UP:    // 上箭头
				if(cursorY>0){
					cursorY--;
					cursorX=min(cursorX,static_cast<int>(lines[cursorY].size()));
				}
				break;
			case VK_DOWN:  // 下箭头
                if (cursorY < static_cast<int>(lines.size()) - 1) {
                    cursorY++;
                    cursorX = min(cursorX, static_cast<int>(lines[cursorY].size()));
                }
                break;
            case VK_BACK:
                if (cursorX > 0) {
                    lines[cursorY].erase(cursorX - 1, 1);
                    cursorX--;
                    displayText(lines);
                } else if (cursorY > 0) {
                    cursorX = static_cast<int>(lines[cursorY - 1].size());
                    lines[cursorY - 1] += lines[cursorY];
                    lines.erase(lines.begin() + cursorY);
                    cursorY--;
                    displayText(lines);
                }
                break;
            case VK_DELETE:
                if (cursorX < static_cast<int>(lines[cursorY].size())) {
                    lines[cursorY].erase(cursorX, 1);
                    displayText(lines);
                } else if (cursorY < static_cast<int>(lines.size()) - 1) {
                    lines[cursorY] += lines[cursorY + 1];
                    lines.erase(lines.begin() + cursorY + 1);
                    displayText(lines);
                }
                break;
            case VK_RETURN:
            {
                string prev_line = lines[cursorY].substr(0, cursorX);
                string next_line = lines[cursorY].substr(cursorX);
                lines[cursorY] = prev_line;
                lines.insert(lines.begin() + cursorY + 1, next_line);
                cursorY++;
                cursorX = 0;
                displayText(lines);
//                SetCursorPos(cursorX,cursorY);
                break;
            }
            case VK_TAB:
            {
            	lines[cursorY].insert(cursorX,"    ");
            	cursorX+=4;
            	displayText(lines);
            	break;
        	}
			default:
                if (key.uChar.AsciiChar != 0 && isprint(key.uChar.AsciiChar)) {
                    lines[cursorY].insert(cursorX, 1, key.uChar.AsciiChar);
                    cursorX++;
                    displayText(lines);
//                    SetCursorPos(cursorX,cursorY);
                }
                break;
		}
		SetPos(cursorX,cursorY);
	}
	// 恢复控制台模式
	setCursorVisibility(false);
    restoreConsoleConfig();
    cout << "Enter any key to return to the file manager simulator..." << endl;
    system("pause > nul");
    return saveSuccess;
}
 
// 对外暴露的编辑入口(对接你的文件管理系统)
void editFile() {
    string filename;
    cout<<"input the file to edit:";
    cin >> filename;
 
    // 1. 检查当前目录是否存在该文件(用你系统的内存记录判断)
    if (!a[now].mp_file[filename]) {
    	cout<<"Sorry , there's no file named \" "<<filename<<" \" !"<<endl;
//        cout<<"错误:当前目录下没有名为 \""<<filename<<"\" 的文件!"<<endl;
        system("pause > nul");
        return;
    }
 
    string real_file_path = buildRealPath() + "\\" + filename;
    cout << "real file path:" << real_file_path << endl; // 新增:打印真实路径,方便确认
    cout << "Entering Edit MODE ( Alt + F to save&quit) ..." << endl;
    system("pause > nul");
    editTextCore(real_file_path);
}
//--------------------------------------------------- 
 
void mkdir(){//"mkdir"
	string new_name;
	cin>>new_name;
	if(mp[new_name]){//SPJ for [under]
		cout<<"already have this directory!"<<endl;
		return;
	}
	dircnt++;
	mp[new_name]=dircnt;           //ID
	fa[ dircnt ] = now;            //son and father
	a[now].son.push_back(dircnt);  //contain ID
	a[dircnt].dep=a[now].dep+1;    //dep
	a[dircnt].dirname=new_name;    //dir_name
	
	//upd:2025/11/19  create a real diretory
    string real_dir_path = buildRealPath() + "\\" + new_name;
    // Windows API:创建目录(支持多级目录,需要设置CREATE_NEW_CONSOLE?不,用CREATE_DIRECTORY)
    BOOL success = CreateDirectoryA(real_dir_path.c_str(), NULL);
    if (success || GetLastError() == ERROR_ALREADY_EXISTS) {
        cout << "Successfully make a directory named\"" << new_name << "\"" << endl;
    } else {
        cout << "Failed to make directory \"" << new_name << "\"! Error code: " << GetLastError() << endl;
    }
}
 
int find_dep(int x,int to_dep){
	if(a[x].dep==to_dep)return x;
	return find_dep(fa[x],to_dep);
}
 
void change_dir(){//"cd"
	string to_name;
	cin>>to_name;
	if(mp[to_name]==0){//SPJ for [under] invalid case
		cout<<"you don't have such a directory ,which named \""<<to_name<<"\""<<endl;
		return;
	}
	int to=mp[to_name],to_dep=a[to].dep;
	now=to;
	cout<<"Loading..."<<endl;
	pos.clear();//as you see
	pos_size=0;
	for(int i=1;i<=to_dep;i++){//start from Desktop (time_eff not good(no care))
		pos.push_back(find_dep(to,i));
		pos_size++;
		
			//dont forget pos_size
			//cout<<"id:"<<find_dep(to,i)<<"  and dir_name:"<<a[find_dep(to,i)].dirname<<endl;
			////test [up];
	}
	cout<<"Successfully changed to \""<<to_name<<"\""<<endl;
}
 
void ret(){//"ret"
	string to_name="Desktop";
	now=1;
	cout<<"Loading..."<<endl;
	pos.clear();
	pos_size=1;
	pos.push_back(1);
	cout<<"Successfully changed to \""<<to_name<<"\""<<endl;
}
 
int overall_now;
 
void list_dir(int now,int blk){//"ls dir"
	cout<<a[now].dirname;
	if(a[now].son.empty() and now == overall_now){
		cout<<endl;
		return;
	}
	if(a[now].son.empty())return;
	cout<<"--";
	
//	int delta=0/*,cnt=1*/;
//	for(auto v:a[now].son)delta=max(delta,int(a[v].dirname.size())+2);
//  that's not true[up]
	
	for(int i=0;i<(int)a[now].son.size();i++){
		if(i==(int)a[now].son.size()-1)cout<<"|-";
		else cout<<"| ";
		int v=a[now].son[i];
		list_dir(v,blk+(int)a[v].dirname.size()+4);
		if(i==(int)a[now].son.size()-1)continue;
		else cout<<endl<<string(blk,' ');
	}
	cout<<endl;
	return ;
}
 
 
void list_fl(int now){//"ls file"
	printf("LISTING...:\n"); 
	if((int)a[now].son_file.size()==0){
		cout<<"However , you have no file under this directory... :("<<endl;
		return;
	}
	for(auto s:a[now].son_file){
		cout<<string(5,' ')<<s<<endl;
	}
	cout<<"total:"<<a[now].filecnt<<endl;
	return;
}
 
void touch(int now,string new_name){
	if(a[now].mp_file[new_name])
	{//SPJ
		cout<<"Already have such a file named \""<<new_name<<"\""<<endl;
//		printf("Already have such a file named \"")//fail...
		return;
	}
	a[now].mp_file[new_name]=++a[now].filecnt; //for dir
	a[now].son_file.push_back(new_name);       //for dir's filr's name(for ls fl)
	tmf[make_pair(now,new_name)]=++tfc;        //for allover
	b[tfc].filename=new_name; 				   //contain its name
	
	//-------upd:2025/11/19
	string real_file_path = buildRealPath() + "\\" + new_name;
    ofstream real_file(real_file_path); // 创建空文件
    if (real_file.is_open()) {
        real_file.close();
        printf("Successully created a file named \"%s\"\n", new_name.c_str());
    } else {
        printf("Failed to create file \"%s\"!\n", new_name.c_str());
    }
}
 
void init_system(){//as you see
EXE_DIR = getExeDir(); // 初始化exe运行目录
 
	for (int i=0;i<=100009;i++)fa[i]=i;    //Union-find
	mp["Desktop"]=1;        //desk_id
	a[1].dirname="Desktop"; //desk_name
	a[1].dep=1;             //desk_dep  
	now=1;                  //cur_pos
	pos.push_back(1);       //cur_path
	            
	SetConsoleOutputCP(936); // 中文编码
    SetConsoleCP(936);
    
	cout<<"<Desktop>:";
}
 
void print_path(){
	cout<<"<";
	for(int i=1;i<=pos_size;i++){
		cout<<a[pos.front()].dirname;
		pos.push_back(pos.front());  
		pos.pop_front();
		if(i!=pos_size)cout<<"/";  
		
		//SPJ
		//using a deque to turn it aside to output
		//your current path
	}
	cout<<">:";
}

struct _4Kgame{
	struct node{
	    bool _1,_2,_3,_4;
	};
	deque<node>q;
	#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
	void init(){
	    srand(time(NULL));
	    for (int i = 1; i <= 10; i++) {
	    	BackToRandom:;
	        node now = {0, 0, 0, 0};
	        if (rand() % 4 == 0) now._1 = 1;
	        if (rand() % 4 == 0) now._2 = 1;
	        if (rand() % 4 == 0) now._3 = 1;
	        if (rand() % 4 == 0) now._4 = 1;
	        if(!now._1 and !now._2 and !now._3 and !now._4)goto BackToRandom;
	        q.push_back(now);
	    }
	}
	
	void flsh() {
	    system("cls");
	    cout<<"Press O+K to exit"<<endl;
	    for (int i = 9; i >= 0; i--) {
	        cout << "  ";
	        node now = q[i];
	        if (now._1) cout << "O ";
	        else cout << "  ";
	        if (now._2) cout << "O ";
	        else cout << "  ";
	        if (now._3) cout << "O ";
	        else cout << "  ";
	        if (now._4) cout << "O ";
	        else cout << "  ";
	        cout << endl;
	    }
	    cout << "-------------" << endl;
	}
	
	int check() {
	    node now = q[0];
	    bool f = KEY_DOWN('F');
	    bool g = KEY_DOWN('G');
	    bool h = KEY_DOWN('H');
	    bool j = KEY_DOWN('J');
	    bool o = KEY_DOWN('O');
	    bool k = KEY_DOWN('K');
	    Sleep(20);
	    if(f)cout<<"F";
	    if(g)cout<<"G";
	    if(h)cout<<"H";
	    if(j)cout<<"J";
	    if(o)cout<<"O";
	    if(k)cout<<"K";
	    if(o==1 and k==1){
	    	return -1;
	    }
	    if(now._1==f and now._2==g and now._3==h and now._4==j){
	    	return 1;
	    }else return 0;
	}
	
	void solve(){
	    init();flsh();
	    while (1) {
	    	int cn=check();
	        if (cn==1) {
	            q.pop_front();
				Back_to_random_solve:;
	            node now={0, 0, 0, 0};
	            if(rand()%4==0)now._1=1;
	            if(rand()%4==0)now._2=1;
	            if(rand()%4==0)now._3=1;
	            if(rand()%4==0)now._4=1;
	            if(!now._1 and !now._2 and !now._3 and !now._4)goto Back_to_random_solve;
	            q.push_back(now);
				flsh();
	        }
			if(cn==0)continue;
			if(cn==-1)return;
	        Sleep(70);
	    }
	}
}_4K;


struct PassSystem{
	map<string,bool>Username;
	map<pair<string,string>,bool>Password;
	string User1="Noivelist";
	string Password1="SJSsjs090121";
	string User2="shanxinhanshifanbotaobaba";
	string Password2="54188";
	void init_User(string User,string pw_u){
		Username[User]=true;
		Password[make_pair(User,pw_u)]=true;
	}
	void Log(){
		init_User(User1,Password1);
		init_User(User2,Password2);
		bool is_Passed=false;
		while(!is_Passed){
			string name_now;
			cout<<"Please key in the username:";
			cin>>name_now;
			if(Username[name_now]){
				string pw_now;
				cout<<"Now key in the password:";
				cin>>pw_now;
				if(Password[make_pair(name_now,pw_now)]){
					cout<<"Login Successfully!"<<endl;
					return;
				}
				else cout<<"Wrond Password!"<<endl;
			}
			else cout<<"Username not exist!"<<endl;
		}
	}
}Login;
 
int main(){
	Login.Log();
	init_system();
	while(1){
		string tmp;
		cin>>tmp;
		if(isdigit(tmp[0])){
			cout<<tmp<<endl;
			print_path();
		}
		if(!isdigit(tmp[0])){
			if(tmp=="ret"){
				ret();
				print_path();
				continue;
			}
			if(tmp=="mkdir" or tmp=="md"){
				mkdir();
				print_path();
				continue;
			}
			if(tmp=="cd"){
				change_dir();
				print_path();
				continue;
			}
			if(tmp=="ls"){
				string ty;
				cin>>ty;
				if(ty=="dir") overall_now=now,list_dir(now,a[now].dirname.size()+2);
				if(ty=="file")  list_fl(now);
				print_path();
				continue;
			}
			if(tmp=="ld"){
				overall_now=now,list_dir(now,a[now].dirname.size()+2);
				print_path();
				continue;
			}
			if(tmp=="lf"){
				list_fl(now);
				print_path();
				continue;
			}
			if(tmp=="touch" or tmp=="touhc"){
				string ty;
				cin>>ty;
				touch(now,ty);
				print_path();
				continue;
			}
			if(tmp=="shut"){
				cout<<endl<<"Shut down the system successfully!"<<endl;
				cout<<"Have a good day!"<<endl;
				exit(0);
			}
			if(tmp=="cls"){
				system("cls");
				print_path();
				continue;
			}
			if(tmp=="edit"){
				editFile();
				print_path();
				continue;
			}
			if(tmp=="game"){
				_4K.solve();
				system("cls");
				print_path();
				continue;
			}
			cout<<"Such Command is not exist!"<<endl;
			print_path();
		}
	}
	return 0;
}
/**
 * g++ a.cxx
 * ./a.out
 * 
 * 
 **/
posted @ 2025-11-24 21:09  Noivelist  阅读(26)  评论(0)    收藏  举报