操作系統: 二級文件夾文件系統的實現(c/c++語言)


操作系統的一個課程設計,實現一個二級文件夾文件系統。

用disk.txt模擬磁盤,使用Help查看支持的命令及其操作方式,root為超級用戶(寫在disk.txt中) 文件的邏輯結構:流式文件。 物理結構:鏈接文件。

物理空間管理:空暇鏈法。

文件夾結構:二級文件夾結構。 文件夾搜索技術:線性搜索。

FCB:含文件相關的所有屬性。

 物理盤塊的設計(disk.txt)

以一個文本文件disk.txt模擬硬盤,設定硬盤容量分為100個物理塊,每一個物理塊的大小512字節(為了測試方便,最后68個數據塊每一個的大小為256字節),盤塊之間用(‘\n’)切割。

因此一個盤塊:512字節數據+1字節(\n)切割符=513字節。則disk.txt 長度=51300(100×513)+1字節(文件結束符)=51301字節。

100塊盤塊的分布:

1: MFD塊,存放MFD信息;

217: UFD塊,存放UFD信息;

1833: UOF塊,存放UOF信息;

其余物理塊用於存放文件內容。

# MFD塊的設計

硬盤的第1個物理塊固定用於存放主文件文件夾MFDMFD結構例如以下:

typedef struct mfd{
  username ;//username 14B
  userpwd ;//password14B
  link;  //該用戶的UFD所在的物理塊號(4B)
}MFD;

每一個MFD項占32字節。因此,1個物理塊可存放512/32=16MFD(用戶),即本文件系統最多可管理16個用戶。例如以下表1所看到的:

username

password

用戶文件文件夾地址

Peter

12345

3

Ben

Abc

5

         表文件系統用戶文件夾信息表

2#-17# UFD塊的設計

2#17#物理塊:固定用於存放用戶文件文件夾UFD

假設一個用戶須要一個UFD塊。因此,16個用戶共須要16UFD塊。

UFD結構例如以下:

typedef struct {
 filename  //文件名稱14B;
 mode;  ///文件權限0-readonly;1-writeonly;2-read/write
 length; ///文件長度(以字節數計算)
 addr;//該文件的第1個文件塊對應的物理塊號
}UFD;

一個UFD項設為32 Bytes。一個塊可存放16UFD項。則一個用戶最多可創建16個文件。例如以下表2所看到的:

Filename

Mode

Length

Addr

A

1

3

50

B

2

5

52

                                                                                                                                      表用戶文件文件夾信息表

18#-33# UOF塊的設計

18#-33#物理塊:固定用於存放主文件文件夾UOF,假定一個用戶須要一個塊存放UOF。一個UOF項占32字節,則一個塊可存放512/3216UOF,即一個用戶可同一時候打開的文件數為16個。用戶已打開表”(UOF)。用以說明用戶當前正在使用文件的情況。

假設用戶最多同一時候找開或建立16個文件。則用戶已打開文件表UOF應該有16個登記欄,結構例如以下表3所看到的:

文件名稱

文件屬性

狀態(打開/建立)

讀指針

寫指針

應該為16個登記欄

                                   表主文件文件夾信息表

用戶請求打開或建立一個文件時。對應的文件操作把有關該文件的信息登記到UOF中。讀指針和寫打針用於指出對文件進行存取的對應位置。

 34#-100# 數據塊的設計

34#-100#:數據塊(物理塊每一個256字節),用於存放文件內容;為了實現物理塊的分配和回收,程序始終維護一個空暇物理塊表。以物理塊號從小到大排列。

物理塊以鏈接分配方式,以最先適應法從空暇表中分配。

數據結構例如以下:

typedef struct cluster
{Num ;////物理塊號
long  nextcluster;/////指向下一物理塊號
}Cluster;

主要結構分析清楚了之后,程序流程圖就不在這里畫了。

我使用的二維vector存儲這些結構體,每次程序啟動的時候先從文件里讀取這些信息至內存,各種信息直接在內存中改動。使用sysc指令將內存中的信息同步至disk.txt。

須要注意的幾個問題:

(一)函數指針的運用

在眾多對輸入命令的函數處理中,假設採用if..else..或者switch..case..的方法勢必會造成代碼的冗余以及代碼簡潔度的缺失。在這里我用到了函數指針的方法,定義一個結構體專門用於存儲命令的字符串和對應的函數處理名稱(函數指針),這樣僅僅須要一次for循環遍歷就能夠簡潔高效的處理這些命令,既體現了代碼規范中的簡潔高效的規則,又幫助自己深刻理解了C++語法中函數指針的應用。

typedef void(*func)(void);
typedef struct hand
{
	char *pname;
	func handler;
}HAND_TO;

HAND_TO handlerlist[] =
{
	{ "Chmod", do_Chmod },
	{ "Chown", do_Chown },
	{ "Mv", do_Mv },
	{ "Copy", do_Copy },
	{ "Type", do_Type },
	{ "Passwd", do_Passwd },
	{ "Login", do_Login },
	{ "Logout", do_Logout },
	{ "Create", do_Create },
	{ "Delete", do_Delete },
	{ "Open", do_Open },
	{ "Close", do_Close },
	{ "Write", do_Write },
	{ "Read", do_Read },
	{ "Help", do_Help },
	{ "dir", do_dir},
	{ "sysc",do_sysc},
	{ "Register", do_register},
	{ "Exit", do_exit},
	{ "Clear", do_Clear},
	{ NULL, NULL }
};


(二)文件物理塊的設計

在對文件內容的分塊存儲中。由於UOF中僅僅記錄了文件內容的起始物理塊。這對於寫指針來說定位當前位置是能夠實現的,由於我僅僅須要記錄最后一個物理塊的偏移量就可以。追加寫入的時候直接迭代到最后一個物理塊進行寫入。

可是對於讀指針來說。僅僅記錄最后一個物理塊的偏移量是不能夠的,由於我上一次讀的位置不一定位於文件的末尾,這樣就會產生沒有數據記錄當前讀的物理塊的塊號。對此我的解決方法是讀指針記錄當前字節的總數,這樣讀指針/256能夠得出當前的物理塊的塊號。讀指針%256能夠得出當前讀的物理塊的偏移量。

問題得到了完美的解決。

void do_Write()
{
	//Write	filename buffer nbytes 寫文件   物理空間68

	int is_ok = 0;
	for (int i = 0; i < FileState[curID].size(); i++)
	{
		if (strcmp(FileState[curID][i].filename, cmd_in.cmd_num[1].c_str()) == 0)
		{
			is_ok = 1;
			break;
		}
	}
	if (is_ok == 0)
	{
		cout << "文件尚未打開!

" << endl; return; } char buf[1024]; stringstream ss; ss << cmd_in.cmd_num[3]; int temp; ss >> temp; for (int i = 0; i < FileInfo[curID].size(); i++) { if (strcmp(FileInfo[curID][i].filename, cmd_in.cmd_num[1].c_str()) == 0) { if (FileInfo[curID][i].mode == 1 || FileInfo[curID][i].mode == 2)//推斷權限 { break; } else { cout << "沒有寫的權限!" << endl; return; } } } int index; for (int i = 0; i < FileState[curID].size(); i++) { if (strcmp(FileState[curID][i].filename, cmd_in.cmd_num[1].c_str()) == 0) { index = i; break; } } //起始物理塊 int address; for (int i = 0; i < FileInfo[curID].size(); i++) { if (strcmp(FileInfo[curID][i].filename, cmd_in.cmd_num[1].c_str()) == 0) { address = FileInfo[curID][i].addr; break; } } //注意:此處發生了更改。 cout << "請輸入buff的內容:" << endl; gets(buf); fflush(stdin); //strcpy(buf, cmd_in.cmd_num[2].c_str()); int wbegin; wbegin = FileState[curID][index].write_poit; //找到寫指針所在的最后一個磁盤 while (FileCluster[address].next_num != address) address = FileCluster[address].next_num; vector <int> newspace_num;//計算將要占用的物理塊的數量 newspace_num.clear(); //int num = (256-wbegin+temp) / 256-1; if (temp <= 256 - wbegin) num = 0; else { num = ceil((temp - (256 - wbegin))*1.0 / 256); } newspace_num.push_back(address); //cout << newspace_num.size() << endl;// for (int i = 0; i < FileCluster.size(); i++) { if (newspace_num.size() == num+1) break; if (FileCluster[i].is_data == 0) { newspace_num.push_back(i); FileCluster[i].is_data = 1; } } for (int k = 0; k < newspace_num.size() - 1; k++) { FileCluster[newspace_num[k]].next_num = newspace_num[k + 1]; } for (int i = 0; i < temp; i++) { if (wbegin == 256) { wbegin = 0; address = FileCluster[address].next_num; } FileCluster[address].data[wbegin] = buf[i]; wbegin++; } //更新寫指針 FileState[curID][index].write_poit = wbegin; cout << "磁盤寫入成功!" << endl; return; }


本實驗所有源代碼請到我的  Github下載,也歡迎大家fork繼續進行完好。





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM