一图焰、程序概述
1. 基本概述
這次大作業(yè)是在centos 7系統(tǒng)下完成的启盛,使用的編程語言為:c++。
存放路徑為:/home/null/workspace
2. 實(shí)現(xiàn)功能
完成了要求實(shí)現(xiàn)的基本命令及部分可選做的擴(kuò)展命令
1技羔、pwd ?//顯示當(dāng)前所在目錄的路徑名
2僵闯、list ?<目錄名> ?????????//列出指定目錄名中的所有目錄及文件
3、cd ?<目錄名或路徑>???//改變當(dāng)前工作目錄
4藤滥、mkdir<目錄名> ????//新建目錄
5鳖粟、rmdir ?<目錄名>??????//刪除目錄
6、exit?????????????????//退出命令解釋程序
7拙绊、rename <舊文件名> <新文件名> ?//重命名一個(gè)文件或目錄
8向图、copy <已存在的文件名及其路徑> <副本文件名及其路徑>??//復(fù)制一個(gè)已存在的文件
二、設(shè)計(jì)思路
本次大作業(yè)要求使用c++标沪,而且必須在linux的環(huán)境下操作榄攀,于是我使用了很多在linux下的函數(shù)庫。
1金句、函數(shù)說明
1檩赢、getcwd()函數(shù)
char * getcwd(char * buf,size_t size);
getcwd()會(huì)將當(dāng)前的工作目錄絕對(duì)路徑復(fù)制到參數(shù)buf所指的內(nèi)存空間,參數(shù)size為buf的空間大小趴梢。
用于實(shí)現(xiàn)pwd的命令解釋漠畜,顯示當(dāng)前目錄所在的文件名。
2坞靶、opdir()函數(shù)&readdir()函數(shù)&closedir()函數(shù)
DIR *opendir(const char *name);
它返回一個(gè)DIR*類型憔狞,這是一個(gè)句柄,并且這個(gè)句柄要傳給reddir函數(shù)彰阴。
struct dirent *readdir(DIR *dir);
該參數(shù)是opendir函數(shù)返回的句柄瘾敢,而該函數(shù)的返回值是struct dirent* 類型。
該結(jié)構(gòu)體:
struct dirent {
ino_t????????? d_ino;?????? /* inode number */
off_t????????? d_off;?????? /* offset to the next dirent */
unsigned short d_reclen;??? /* length of this record */
unsigned char? d_type;????? /* type of file */
char?????????? d_name[256]; /* filename */
};
這個(gè)結(jié)構(gòu)體的d_name存放的就是文件的名字,這里的文件包括普通文件簇抵,目錄文件等等庆杜,在linux的思想中,所有的東西都是文件碟摆。
int closedir(DIR *dir);
在結(jié)束時(shí)使用晃财,用于關(guān)閉dir。
用于實(shí)現(xiàn)list的命令解釋典蜕,列出指定目錄名中的所有目錄及文件断盛。
3、chdir()函數(shù)
int chdir (const char *pathname);
進(jìn)程調(diào)用該函數(shù)可以改變當(dāng)前工作目錄
用于實(shí)現(xiàn)cd的命令解釋愉舔,改變當(dāng)前工作目錄钢猛。
4、mkdir()函數(shù)
int mkdir(const char *pathname, mode_t mode);
用mode的方式創(chuàng)建以pathname命名的目錄轩缤。如/home/null/helloworld 創(chuàng)建的文件夾名字則為helloworld命迈。mode用于定義創(chuàng)建目錄的權(quán)限 如?:
//00700權(quán)限,代表該文件所有者擁有讀火的,寫和執(zhí)行操作的權(quán)限
//00070權(quán)限壶愤,代表該文件用戶組擁有讀,寫和執(zhí)行操作的權(quán)限
而我使用的mode_t 0777為八進(jìn)制 轉(zhuǎn)換成二進(jìn)制為 000 111 111 111 對(duì)應(yīng)為可讀可寫可執(zhí)行卫玖,
每三個(gè)為一組公你。 分別為文件所有者,用戶者假瞬,其他用戶陕靠。即所有用戶擁有可讀可寫可執(zhí)行的權(quán)限。
用于實(shí)現(xiàn)mkdir的命令解釋脱茉,新建目錄剪芥。
5、rmdir()函數(shù)
int _rmdir(const char *dirname);
調(diào)用該函數(shù)刪除dirname的目錄
用于實(shí)現(xiàn)rmdir的命令解釋琴许,刪除目錄税肪。
6、rename()函數(shù)
int rename(const char * oldpath,const char * newpath);
調(diào)用該函數(shù)將參數(shù)為oldpath的文件重命名為參數(shù)為newpath的文件榜田,若newpath所指定的文件已存在益兄,則會(huì)被刪除。
用于實(shí)現(xiàn)rename的命令解釋箭券,刪除目錄净捅。
7、open()函數(shù)&read()函數(shù)&write()函數(shù)
int open(constchar* pathname,int flags,mode_tmode);其中最后一項(xiàng)為可選項(xiàng)辩块。
調(diào)用該函數(shù)可以打開參數(shù)為pathname的文件蛔六,參數(shù)flag可以決定用什么方式打開文件荆永。eg:
O_RDONLY 以只讀方式打開文件。
O_WRONLY 以只寫方式打開文件国章。
O_RDWR 以可讀寫方式打開文件具钥。上述三種旗標(biāo)是互斥的,也就是不可同時(shí)使用液兽,但可與下列的旗標(biāo)利用OR(|)運(yùn)算符組合骂删。
O_CREAT 若欲打開的文件不存在則自動(dòng)建立該文件。
ssize_t? read(int fd,void * buf ,size_t count);
調(diào)用該函數(shù)可以由已打開的文件讀取數(shù)據(jù)抵碟。read()會(huì)把參數(shù)fd 所指的文件傳送count個(gè)字節(jié)到buf指針?biāo)傅膬?nèi)存中桃漾。若參數(shù)count為0坏匪,則read()不會(huì)有作用并返回0拟逮。返回值為實(shí)際讀取到的字節(jié)數(shù),如果返回0适滓,表示已到達(dá)文件尾或是無可讀取的數(shù)據(jù)敦迄,此外文件讀寫位置會(huì)隨讀取到的字節(jié)移動(dòng)。簡單來說就是從fd中調(diào)count個(gè)字節(jié)到緩沖字符區(qū)buf中凭迹。
ssize_t write (int fd,const void * buf,size_t count);
調(diào)用該函數(shù)參數(shù)buf所指的內(nèi)存(read中的緩沖區(qū))寫入count個(gè)字節(jié)到參數(shù)fd所指的文件內(nèi)罚屋。
用于實(shí)現(xiàn)copy的命令解釋,復(fù)制一個(gè)已存在的文件嗅绸。
三脾猛、詳細(xì)設(shè)計(jì)
1、int main()
while(1) {
? ? ? //shell prompt
? ? ? cout<<"[null@]$";
? ? ? cin>>str;? ?
if(str == "pwd"){
? ? ? ? pwd();}
? ? ? else if(str == "list"){
? ? ? ? list();}
.....}
如流程圖所示鱼鸠,在輸出提示后則進(jìn)入一個(gè)死循環(huán)給str賦值猛拴,當(dāng)輸入的str為可執(zhí)行命令時(shí)則進(jìn)入函數(shù),執(zhí)行完畢后等待下一個(gè)命令蚀狰。
2愉昆、void pwd();
顯示當(dāng)前絕對(duì)工作路徑。
char ptr[40];
?getcwd(ptr,sizeof(ptr));?
?cout<<ptr<<endl;?
調(diào)用getcwd()函數(shù)麻蹋,直接獲取當(dāng)前路徑至ptr中跛溉,直接輸出即可。
3扮授、int list();? ?
列出指定目錄名中的所有目錄及文件芳室。
? ? char path[20];
? ? cin>>path;? ?
? ??// char path[]="/home/null/workspace";
? ? const char *ptr=path;? //進(jìn)入函數(shù)后,輸入路徑保存在path中刹勃,并轉(zhuǎn)換為opdir支持的const char格式堪侯。
? ? DIR *dir; //聲明一個(gè)句柄'dir'
? ? struct dirent *file; //readdir函數(shù)的返回值就存放在這個(gè)結(jié)構(gòu)體中,所要查找的文件名也放在這里深夯,用指針的方式就可以查找抖格。
? ? int len = 0;
? ? int i;
? ? char filename[256][256];
? ? if(!(dir = opendir(ptr))) //如果需要打開的目錄不存在
? ? {
? ? ? // printf("error path : %s!\n",path);
? ? ? ? cout<<"error path:"<<path<<endl; //輸出錯(cuò)誤的路徑
? ? ? ? return -1;}
? ? while((file = readdir(dir)) != NULL)
? ? {
? ? ? ? if(strncmp(file->d_name, ".", 1) == 0) //把當(dāng)前目錄'.'诺苹,上一級(jí)目錄'..'去除
? ? ? ? ? ? continue;
? ? ? ? strcpy(filename[len++], file->d_name); //保存遍歷到的文件名}
? ? closedir(dir); //關(guān)閉dir流
? ? for(i = 0; i < len; i++)
? ? {cout<<filename[i]<<" ";}
? ? cout<<endl;
? ? return 0;
進(jìn)入函數(shù)后,需要輸入查找得目錄的絕對(duì)路徑path雹拄,若opendir返回值為0收奔,即打開目錄錯(cuò)誤,則輸出錯(cuò)誤路徑滓玖,跳出函數(shù)坪哄。若打開成功則跳過if語句。隨后執(zhí)行?while((file = readdir(dir)) != NULL)語句势篡,當(dāng)讀出來的file不為空則一直循環(huán)翩肌。第一個(gè)if語句是把所有'.'開頭文件及文件夾去掉,因?yàn)樵贚inux中‘.’ ‘..’ ‘.xxx’為當(dāng)前目錄禁悠,上一級(jí)目錄及隱藏文件念祭,不符合我們要查找的內(nèi)容。執(zhí)行完循環(huán)后則輸出查找到的文件夾并退出循環(huán)碍侦。
4粱坤、void cd();
改變當(dāng)前工作目錄
??char dirname[20];
? cin>>dirname;
? if(chdir(dirname) == -1)
? {? cout<<"the directory isn't exit!"<<endl; }
輸入要進(jìn)入的目錄,調(diào)用linux c函數(shù)庫的chdir()函數(shù)執(zhí)行chadir命令瓷产。若返回值為1則cd命令輸入錯(cuò)誤(文件夾不存在)站玄。
5、void _mkdir();
新建目錄
? char filename[20]; cin >> filename;
? if(mkdir(filename, 0777) == 0)? {
? ? cout<<filename<<" created successful!"<<endl;}
? else {? cout<<filename<<" created unsuccessful!"<<endl;}
輸入要?jiǎng)?chuàng)建的文件夾名稱濒旦,調(diào)用linux c函數(shù)庫的mkdir()函數(shù)執(zhí)行makedir命令株旷。若返回值為0則mkdir命令執(zhí)行成功。
6尔邓、void _rmdir();
刪除目錄
char filename[20];
? cin >> filename;
? if(rmdir(filename) == 0)? ?{
? ? cout<<filename<<" deleted successful!"<<endl;}
? else? cout<<filename<<" deleted unsuccessful!"<<endl;
輸入要?jiǎng)h除的文件/文件夾名稱晾剖,調(diào)用linux c函數(shù)庫的rmdir()函數(shù)執(zhí)行deldir命令。若返回值為0則deldir命令執(zhí)行成功铃拇。
7钞瀑、void _rename();
重命名一個(gè)文件或目錄
? char filename[20], filename1[20];
? cin>>filename>>filename1;
? if(rename(filename,filename1) == 0)
? {? cout<<"changed successful!"<<endl;}
? else cout<<"changed unsuccessful!"<<endl;
輸入要重命名的舊文件/文件夾名稱以及新文件/文件夾名稱,調(diào)用linux c函數(shù)庫的rename()函數(shù)執(zhí)行rename命令慷荔。若返回值為0則rename命令執(zhí)行成功雕什。
8、void copy();
復(fù)制一個(gè)已存在的文件
char src[20],des[20];
char buff[1024];
int temp; //讀出了多少個(gè)字節(jié)
cin>>src>>des;
int fd,fd2;
fd = open(src,O_RDWR|O_CREAT);
fd2 = open(des,O_RDWR|O_CREAT);
while(temp = read(fd,buff,1024))
{write(fd2,buff,temp);}
?cout<<"copy successful!"<<endl;
輸入需要復(fù)制的文件路徑賦值至src显晶,輸入需要將復(fù)制的文件到的絕對(duì)路徑至des贷岸。用open函數(shù)以O(shè)_RDWR|O_CREAT的旗標(biāo)打開這兩個(gè)路徑 。O_RDWR|的含義是以可讀寫方式打開文件磷雇。O_CREAT 的含義是若欲打開的文件不存在則自動(dòng)建立該文件偿警。將fd的文件每次以1024個(gè)字節(jié)讀入緩沖數(shù)組buff中,并用temp讀出返回值(讀了多少個(gè)字節(jié))唯笙,再將fd的文件以每次temp個(gè)字節(jié)將buff中的數(shù)組寫入fd2中螟蒸。
缺點(diǎn):檢測不到復(fù)制失敗的情況盒使。
四、使用情況
五七嫌、小結(jié)
1少办、遇到的困難
寫了一段時(shí)間的python對(duì)于這種接近底層的語言感到陌生,c++不像別的語言一樣可以有很多打包好的方便的方法诵原,也不像python一樣可以不用定義數(shù)據(jù)類型的使用數(shù)據(jù)英妓。就算有別人打包好的函數(shù),還是有很多算法都是要自己去寫的绍赛,而在linux系統(tǒng)下寫這份大作業(yè)更是需要花時(shí)間去理解Linux c函數(shù)蔓纠,不僅要理解函數(shù)的調(diào)用還要理解參數(shù)的意義和不同情況下的函數(shù)返回值。雖然一開始有一頭霧水的感覺吗蚌,但在查閱了資料和文檔后還是能夠?qū)崿F(xiàn)要求的指令的腿倚。
2、總結(jié)和感想
一開始的時(shí)候褪测,在裝虛擬機(jī)和系統(tǒng)都費(fèi)了不少的心思猴誊,比如虛擬機(jī)要破解、系統(tǒng)有各式各樣的Linux系統(tǒng)侮措,(如Linux Ubuntu 、Centos等等)乖杠、裝系統(tǒng)的時(shí)候裝了minimal 只有一個(gè)黑框框完全不知道該怎么辦分扎,即使查閱了網(wǎng)上的Linux的命令大全也不知道要怎么樣才能編譯c程序。后來通過看教學(xué)視頻(騰訊課堂)和上機(jī)實(shí)驗(yàn)明白了要如何編譯使用C程序和熟悉了一些基本的Linux的命令胧洒,迷上了vi編輯器畏吓。雖然很難用,但用得好只用鍵盤就能完成以前要鼠標(biāo)點(diǎn)來點(diǎn)去的操作卫漫,是一個(gè)能實(shí)實(shí)在在的提高寫代碼效率的編輯器菲饼。也能理解為什么有人那么喜歡Linux系統(tǒng)了哈哈。雖然我為了明天能交作業(yè)用的是gedit
六列赎、參考鏈接
https://blog.csdn.net/wwj_748/article/details/8309440
https://www.cnblogs.com/ace-wu/p/6640186.html (open write read )
https://blog.csdn.net/u014453898/article/details/54864666(linux下的c語言復(fù)制方法)
https://blog.csdn.net/qq_30941699/article/details/55517763(linux下c語言遞歸法查找文件宏悦,并打印絕對(duì)地址)
https://blog.csdn.net/silentob/article/details/76994618(const char * 、char const *包吝、 char * const 三者的區(qū)別)
https://www.cnblogs.com/avril/archive/2010/03/22/1691477.html(int? main(int??argc,??char*??argv[])詳解)
https://blog.csdn.net/jichl/article/details/7948724(ftw遍歷目錄樹)
七饼煞、源代碼
#include<iostream>
#include<cstring>
#include<sys/types.h>
#include<sys/stat.h>
#include<dirent.h>
#include<stdlib.h>
#include<fcntl.h>
#include<time.h>
#include<queue>
#include<ftw.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
using namespace std;
//declare method
void pwd(); ??
int list(); ???
void cd(); ????
void _mkdir();
void _rmdir();
void _rename();
void copy();
int main()
{
cout<<"可執(zhí)行的命令:"<<endl;
cout<<"pwd ????????????????????????????????????????//顯示當(dāng)前所在目錄的路徑名"<<endl;
cout<<"list ????<目錄名> ???????????????????????????//列出指定目錄名中的所有目錄及文件"<<endl;
cout<<"cd ??????<目錄名或路徑> ??????????????????????//改變當(dāng)前工作目錄"<<endl;
cout<<"mkdir ???<目錄名> ???????????????????????????//新建目錄"<<endl;
cout<<"rmdir ???<目錄名> ???????????????????????????//刪除目錄"<<endl;
cout<<"rename ??<舊文件名> <新文件名> ????????????????//重命名一個(gè)文件或目錄"<<endl;
cout<<"copy ?????<已存在的文件名及其路徑> <副本文件名及其路徑> ???//復(fù)制一個(gè)已存在的文件"<<endl;
cout<<"rmdir ???<目錄名> ???????????????????????????//刪除目錄"<<endl;
// cout<<"find ????<目錄> -name <待查找的文件名> ????????//在指定的目錄及其子目錄中查找指定的文件,并輸出查找到的文件的絕對(duì)路徑诗越。"<<endl;
cout<<"exit ???????????????????????????????????????//退出命令解釋程序"<<endl;
???string str;
???while(1) {
??????//shell prompt
??????cout<<"[null@]$";
??????cin>>str; ????
/*
??????switch(str){
????case "pwd":
??????????pwd();
??????????break;
????default:
????cout<<"no command not found"<<endl;
}
*/
??????if(str == "pwd"){
?????????pwd();}
??????else
??????if(str == "list"){
?????????list();}
??????else
??????if(str == "cd"){
?????????cd();}
??????else
??????if(str == "mkdir"){
?????????_mkdir();}
??????else
??????if(str == "rmdir"){
?????????_rmdir();}
??????else
??????if(str == "rename"){
?????????_rename();}
??????else
??????if(str =="copy"){
?????????copy();}
??????else
??????if(str=="exit"){
?????????break;}
??????else
??????cout<<"no command not found"<<endl;
????????????????????????}
????return 0;
}
void pwd()
{
???char ptr[40]; ?
???getcwd(ptr,sizeof(ptr)); ??
???cout<<ptr<<endl; ?
}
int list()
{
????char path[20];
????cin>>path;
// ???char path[]="/home/null/workspace";
????const char *ptr=path;
????DIR *dir; //聲明一個(gè)句柄'dir'
struct dirent *file; //readdir函數(shù)的返回值就存放在這個(gè)結(jié)構(gòu)體中
????int len = 0;
????int i;
????char filename[256][256];
if(!(dir = opendir(ptr))) //如果需要打開的目錄不存在
????{
???????// printf("error path : %s!\n",path);
????????cout<<"error path:"<<path<<endl;
????????return -1;
????}
????while((file = readdir(dir)) != NULL)
????{
????????if(strncmp(file->d_name, ".", 1) == 0) //把當(dāng)前目錄'.'砖瞧,上一級(jí)目錄'..'去除
????????????continue;
strcpy(filename[len++], file->d_name); //保存遍歷到的文件名
????}
????closedir(dir);
????for(i = 0; i < len; i++)
????{
????????cout<<filename[i]<<" ";
????}
????cout<<endl;
????return 0;
}
void cd()
{
???char dirname[20];
???cin>>dirname;
???if(chdir(dirname) == -1)
???{
??????cout<<"the directory isn't exit!"<<endl;
????}
}
void _mkdir()
{
??char filename[20];
??cin >> filename;
??if(mkdir(filename, 0777) == 0)
??{
?????cout<<filename<<" created successful!"<<endl;
???}
???else
???{ ?cout<<filename<<" created unsuccessful!"<<endl;
???}
}
void _rmdir()
{
???char filename[20];
???cin >> filename;
???if(rmdir(filename) == 0)
???{
????cout<<filename<<" deleted successful!"<<endl;
???}
???else
????cout<<filename<<" deleted unsuccessful!"<<endl;
}
void _rename()
{
??char filename[20], filename1[20];
??cin>>filename>>filename1;
??if(rename(filename,filename1) == 0)
??{
????cout<<"changed successful!"<<endl;
???}
???else
?????cout<<"changed unsuccessful!"<<endl;
}
void copy(){
char src[20],des[20];
char buff[1024];
int temp; //讀出了多少個(gè)字節(jié)
cin>>src>>des;
// char const *src_path = argv[1];
// char const *des_path = argv[2];
int fd,fd2;
fd = open(src,O_RDWR|O_CREAT);
fd2 = open(des,O_RDWR|O_CREAT);
while(temp = read(fd,buff,1024))
{
write(fd2,buff,temp);
}
}