摘要:返回值是文件描述符,表示在文件打卡表項的位置在內(nèi)存中,保存著打開文件的位置信息,是系統(tǒng)為我們維護的方便使用的一個符號。這張圖就是一個最簡單的文件系統(tǒng),但是作業(yè)要求我們有和數(shù)據(jù)塊的分配回收,所以我們得加上位示圖和數(shù)據(jù)塊的位示圖。
?寫在前面?
學(xué)習(xí)一個語言最好的方法是做一個小項目,這個項目不需要多么復(fù)雜,但是一定能激發(fā)你的學(xué)習(xí)興趣。讓我們話不多說,開始吧
本文將帶你手擼一個磁盤組織方式的模擬,你將學(xué)到
全文大約閱讀時間: 30min
??作者簡介:一個從工業(yè)設(shè)計改行學(xué)嵌入式的年輕人
?資源下載:gitee倉庫
?聯(lián)系方式:2201891280(QQ)
完成用戶態(tài)環(huán)境下的磁盤模擬功能,提供磁盤基本信息查詢與格式化功能。
基于C/C++,完成上述完整功能
利用一個大文件(128MB)來模擬磁盤塊設(shè)備,基于固定分片大小實現(xiàn)文件系統(tǒng)的超級塊區(qū)、inode節(jié)點區(qū)、數(shù)據(jù)分片區(qū)的管理,具備磁盤格式化、文件系統(tǒng)查詢(如:fdisk -l)功能,支持文件的inode節(jié)點和對應(yīng)數(shù)據(jù)分片的分配、回收。
注:此為樓主的一次linux作業(yè),鑒于還沒到提交作業(yè)的截至日期,所以如果你 借鑒 此篇文章,請修改一定量以防大家都沒分數(shù)0.0
拿到一道要求時,最重要的是學(xué)會找資源,找到一些思路,然后自己去做實現(xiàn)。
所以我平時很喜歡問思路的同學(xué),但是知道思路還不知道代碼怎么寫呢,我就覺得這是態(tài)度問題了,希望大家還是只借鑒思路,千萬別直接復(fù)制粘貼,這對自己一點好處都沒有。
文件系統(tǒng)簡單模擬
這篇文章實現(xiàn)的功能非常復(fù)雜,所以我只是借鑒了主程序的寫法,主要是給自己做一個主程序的基礎(chǔ)架構(gòu)。
ext2文件系統(tǒng)詳解
這篇文件非常詳細的介紹了ext2文件系統(tǒng)的實現(xiàn)方式,這是已有的真實文件系統(tǒng)的結(jié)構(gòu),我們可以對其進行適當?shù)木?,做出我們的想要的功能?/p>
- 分片大?。?KB 則一共有32K(128M/4K)個分片
- 保留區(qū):三個分片,分別為超級塊,inode位示圖,數(shù)據(jù)區(qū)位示圖
- inode節(jié)點:128B,每個分片有32個inode節(jié)點,32K個分片需要1K個分片保存inode節(jié)點信息,分配inode節(jié)點區(qū)為4MB。
對應(yīng)的分配方式如下圖
做一個類似于終端的執(zhí)行方式,輸入相應(yīng)的命令執(zhí)行相應(yīng)的操作。
基本的效果如下
為了細化上面提到一些細節(jié)實現(xiàn),我們需要了解linux的對文件的系統(tǒng)調(diào)用。這部分有點枯燥,畢竟都是系統(tǒng)調(diào)用函數(shù),但是也不多,熟悉這部分的同學(xué)直接跳過啦0.0
int open (const char *name, int flags, mode_t mode);int close(int fd);
上面對應(yīng)的就是打開和open和close系統(tǒng)函數(shù)定義
其中open有三個傳入?yún)?shù)
- 第一個就很好理解就是文件名稱
- 第二個是flags表示打開方式,這次用到的只有三個 O_CREAT、O_WRONLY、
O_RDONLY分別表示如果不存在就創(chuàng)建,只讀和只寫。其中如果我想獲取讀寫權(quán)限可以用 O_WRONLY|O_RDONLY 來表示。- 第三個參數(shù)我是再第二個參數(shù)有O_CREAT時候使用,是定義文件的權(quán)限的。因為是為了學(xué)習(xí),我就簡單的定義的所有人可讀可寫可執(zhí)行S_IRWXO|S_IRWXG|S_IRWXU。
- 返回值是文件描述符,表示在文件打卡表項的位置(在內(nèi)存中,保存著打開文件的位置信息),是系統(tǒng)為我們維護的方便使用的一個符號。如果返回-1表示打開失敗
相對來說close就簡單很多
- 只有一個傳入?yún)?shù) 就是open的返回值文件描述符,是一個大于等于0的整數(shù)可以看下圖
size_t read(int fd, void *buf, size_t count);size_t write(int filedes,const char* buf,size_t nbytes);
這兩個函數(shù)很類似,只不過功能一個是讀一個是寫,我就放在一起講了。都有三個參數(shù)
- 第一個參數(shù)是一個文件打開表項,其實就是我們剛才說的open返回值。
- 第二個是一個指針,如果忽略他的類型可以理解為一片內(nèi)存空間,其中read就是往這片空間寫入數(shù)據(jù),wirte就是將對應(yīng)的空間的數(shù)據(jù)寫入文件。
- 第三個數(shù)據(jù)是讀或者寫的數(shù)據(jù)大小,單位是字節(jié)。千萬別超過第二個參數(shù)中指針指向的數(shù)據(jù)大小,不然會寫入未知內(nèi)存,造成程序未知錯誤,建議直接就sizeof(第二個元素)
這兩個函數(shù)可以說對于c語言指針的使用極度舒適,直接操作內(nèi)存。
需要注意一個點就是每次讀寫系統(tǒng)會將我們的文件偏移量往后推移讀到元素個數(shù)
#include
#include off_t lseek(int fd, off_t offset, int whence); 上面說到每次read和wirte都會推進文件偏移量。所以為了改變文件偏移量,我們就有了這個函數(shù)。
- 第一個參數(shù)還是文件打開表項,就是open返回那個
- 第二個參數(shù)就是偏移量。單位是字節(jié),可前可后,所以就可以正也可以負值。
- 第三個參數(shù)是相哪里的位置 有三個可選項SEEK_SET、SEEK_CUR、SEEK_END,分別表示相對文件頭、相對當前位置以及相對文件末尾。我們只需要前兩個就好了。
上面就是所有需要的基本系統(tǒng)調(diào)用函數(shù),接下來介紹一些燒腦的文件結(jié)構(gòu)。
圖片是一個常見的文件系統(tǒng)的圖片,我們需要實現(xiàn)的只有單分區(qū)就好了,不那么復(fù)雜。
這張圖就是一個最簡單的文件系統(tǒng),但是作業(yè)要求我們有inode和數(shù)據(jù)塊的分配回收,所以我們得加上inode位示圖和數(shù)據(jù)塊的位示圖。
當我們嘗試訪問一個文件/123/456.txt的時候基本過程是
從這個過程中我們知道
主函數(shù)主要是為了打開文件系統(tǒng)以及給一定的提示信息。
void help(){ printf("****************************************************/n"); printf("*歡迎來到xinglei 的文件系統(tǒng)!?。? /n"); printf("*主要的功能介紹 /n"); printf("* 0.創(chuàng)建系統(tǒng) :create_filesystem /n"); printf("* 1.格式化 :init /n"); printf("* 2.低級格式化:low_init /n"); printf("* 3.查看信息 :info /n"); printf("* 4.創(chuàng)建文件 :mkfile /n"); printf("* 5.查看位示圖:weishitu /n"); printf("* 6.刪除文件 :delfile /n"); printf("* 8.幫助信息 :help /n"); printf("* 9.顯示文件 :ls /n"); printf("* 10.退出 :quit /n"); printf("****************************************************/n");}
主要就是打印一些提示信息,方便用戶使用這個系統(tǒng)。
char* command[] = {"create_filesystem","init","low_init","info","mkfile","weishitu","delfile","deldir","help","ls","quit"};int commandnum = sizeof(command)/sizeof(char *);char path[100] = "file_system";//文件系統(tǒng)while(1){ printf("%s$ ",path); scanf("%s",com); choice = i; for(i=0; i<commandnum; ++i) if(strcmp(com,command[i])==0) break; choice = i; if(Disk == -1 && (!(choice == 0|| choice == 10))){//未創(chuàng)建文件只能退出或者創(chuàng)建文件 printf("文件系統(tǒng)未創(chuàng)建,請創(chuàng)建文件系統(tǒng)。"); continue; } int a; read(Disk,&a,sizeof(int)); if(Disk != -1 &&a == 0 && !(choice == 1 || choice == 2)){ printf("未格式化,請格式化."); lseek(Disk,-sizeof(int),SEEK_CUR); continue; } lseek(Disk,-sizeof(int),SEEK_CUR); switch(choice){ case 0://創(chuàng)建系統(tǒng) create_filesystem(); break; case 1://格式化 init(1); break; case 2://低級格式化 low_init(); break; case 3://查看信息 info(); break; case 4://創(chuàng)建文件 printf("輸入你要創(chuàng)建的文件名: "); char filename[20]; scanf("%s",filename); create_file(filename); break; case 5://查看位示圖 weishi(); break; case 6://刪除文件 printf("請輸入你要刪除的文件:"); char delname[20]; scanf("%s",delname); delfile(delname); break; case 8://幫助信息 help(); break; case 9://顯示文件 ls(); break; case 10: //退出系統(tǒng) quit = 1; break; default: printf("%s command not found/n",com); }
很顯然,我定義了一個while1,然后根據(jù)輸入命令的比較結(jié)果來選擇執(zhí)行哪個分支,默認就是重新回到開頭。在程序運行的時候我已經(jīng)做了打開文件的操作,因為我第超級塊的前4個字節(jié)的數(shù)據(jù)是固定的不為0,所以我可以用它來判斷是否已經(jīng)格式化,然后其它的就是跳轉(zhuǎn)到相應(yīng)的功能中就好了0.0
這只是基礎(chǔ)程序框架,我們其它功能使用另外一個文件來實現(xiàn)
上面我們已經(jīng)實現(xiàn)了基礎(chǔ)的程序功能,這部分我們要深入細節(jié),完成每一個小功能的實現(xiàn)。
?超級塊
就是像剛才說的保存基礎(chǔ)信息
typedef struct{ int inodes_count, blocks_count; //超級塊和indoe總數(shù) int free_inodes_count, free_blocks_count; //未使用block和inode量 short block_size, inode_size; //block和indoe大小 B int first_data_block, first_inode_block; //第一塊數(shù)據(jù)塊第一塊inode節(jié)點位置 int inode_wei, block_wei; //位示圖所在塊號 short inodes_per_block; //每片中的inode數(shù)目 short frag_size; //每片大小 int root_inode; //根節(jié)點inode號 int size; //總大小B}chao; //超級塊定義
?inode節(jié)點
這應(yīng)該是最簡陋的inode節(jié)點了把?
typedef struct{ int i_mode; //文件類型,1表示文件,0文件表示目錄項 int i_size; //文件的大小單位為B int i_blocks; //文件所占塊數(shù) int i_block[15]; //索引節(jié)點 12個直接索引 1個一級索引 2個二級索引}inode; //inode節(jié)點定義
?目錄項
目錄項不用特別復(fù)雜
typedef struct{ char name[28]; int inode;}mulu; //目錄項定義
?位示圖
就簡單的一個位就好了。
unsigned int weishitu[1024];//位示圖定義
這個功能就很簡單,就創(chuàng)建一個128MB的文件就好了。注意判斷是否已經(jīng)存在文件避免覆蓋。
我用了一個4K的數(shù)組循環(huán)32K次寫入來達到128MB0.0
void create_filesystem(){ if(Disk != -1){ printf("已經(jīng)存在文件系統(tǒng)/n"); return; } Disk = open(DISK,O_CREAT|O_WRONLY,S_IRWXO|S_IRWXG|S_IRWXU); int a[1024] = {0}; for(int i = 0;i < 1<<15;i++) write(Disk,(void *)a,sizeof(a));//創(chuàng)建128MB文件 printf("創(chuàng)建文件系統(tǒng)成功/n");}
這部分就億點點復(fù)雜需要做的事情有一些多。
就是重寫超級塊、重寫位示圖、創(chuàng)建根節(jié)點信息。
代碼就不放了 因為太長了-.-
可以在倉庫中找到,我相信你們看得懂
其實我們平時也有用到低級格式化,其實就將所有數(shù)據(jù)置為0。然后再執(zhí)行高級格式化就好了。
void low_init(){ int temp; read(Disk,&temp,sizeof(int)); if(temp){ printf("此操作會清空磁盤,且不可恢復(fù),確定?Y/N "); char s[10]; while(scanf("%s",s) != EOF && !(!strcmp(s,"Y") || !strcmp(s,"N"))) printf("請輸入正確的字符"); if(strcmp(s,"N") == 0){ printf("用戶取消/n"); return ; } } close(Disk); Disk = open(DISK,O_WRONLY); int a[1024] = {0}; for(int i = 0;i < 1<<15;i++) write(Disk,a,sizeof(a));//全部位置置0 close(Disk); Disk = open(DISK,O_RDONLY); printf("低級格式化完成/n"); init(0);}
這里其實和創(chuàng)建文件很類似,但是要注意判斷是否已有系統(tǒng)給與對應(yīng)提示。
這里已經(jīng)簡化了很多了,只做了創(chuàng)建文件,并不寫入數(shù)據(jù),所以就是找空間分配空間,寫入就好了。
但是要實現(xiàn)找inode節(jié)點、找數(shù)據(jù)節(jié)點等多個方法,所以請看源碼。。
相比較而言刪除文件就簡單很多直接將inode和數(shù)據(jù)區(qū)進行回收就好了。
好了,由于很多細節(jié)放代碼過于復(fù)雜今天就寫到這里了。
這只是這次作業(yè)的的一部分,有點難懂,而且做成的也只能在電腦上跑跑看而已,第二部分是一個多線程詞頻統(tǒng)計工具,可以對某個文件目錄所有英文單詞的出現(xiàn)頻率進行統(tǒng)計打印,就有用很多。
如果點贊破百的話,我交作業(yè)前(11.30)肯定能更新出來0.0
海報我都做好了-.-
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/125652.html
摘要:原文從零到一,擼一個在線斗地主上篇作者背景朋友來深圳玩,若說到在深圳有什么好玩的,那當然是宅在家里斗地主了可是天算不如人算,撲克牌丟了幾張不全大熱天的,誰愿意出去買牌啊。 原文:從零到一,擼一個在線斗地主(上篇) | AlloyTeam作者:TAT.vorshen 背景:朋友來深圳玩,若說到在深圳有什么好玩的,那當然是宅在家里斗地主了!可是天算不如人算,撲克牌丟了幾張不全……大熱天的,...
摘要:然而學(xué)習(xí)布局,你只要學(xué)習(xí)幾個手機端頁面自適應(yīng)解決方案布局進階版附源碼示例前端掘金一年前筆者寫了一篇手機端頁面自適應(yīng)解決方案布局,意外受到很多朋友的關(guān)注和喜歡。 十分鐘學(xué)會 Fiddler - 后端 - 掘金一.Fiddler介紹 Fiddler是一個http抓包改包工具,fiddle英文中有欺騙、偽造之意,與wireshark相比它更輕量級,上手簡單,因為只能抓http和https數(shù)據(jù)...
閱讀 3799·2023-01-11 11:02
閱讀 4305·2023-01-11 11:02
閱讀 3126·2023-01-11 11:02
閱讀 5237·2023-01-11 11:02
閱讀 4800·2023-01-11 11:02
閱讀 5573·2023-01-11 11:02
閱讀 5376·2023-01-11 11:02
閱讀 4079·2023-01-11 11:02