Linux中的基础IO(二)
生活随笔
收集整理的這篇文章主要介紹了
Linux中的基础IO(二)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Linux中的基礎IO(二)
文章目錄
- Linux中的基礎IO(二)
- 一、基本接口
- 二、文件描述符
- 三、文件描述符的分配規則
- 四、重定向
- 五、dup2系統調用
- 六、minishell
一、基本接口
int open(const char *pathname, int flags, mode_t mode) const char *pathname:代表要打開或要創建的目標文件。int flags:可傳入多個參數選項,進行或運算組成flags| O_RDONLY | 以只讀的方式打開文件 |
| O_WRONLY | 以只寫的方式打開文件 |
| O_RDWR | 讀,寫打開,(打開方式必須三選一) |
| O_CREAT | 若文件不存在,則創建文件,需要使用mode選項指明新創建文件的權限(mode用函數umask()進行設置當前進程創建的文件的權限掩碼,如umask(0)等) |
| O_APPEND | 追加寫 |
| O_TRUNE | 打開文件時,清空原有文件中的內容 |
如:寫文件
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main() {umask(0);int fd = open("myfile", O_WRONLY|O_CREAT, 0644);if(fd < 0){perror("open");return 1;}int count = 5;const char *msg = "hello bit!\n";int len = strlen(msg);while(count--){write(fd, msg, len);//fd: 文件描述符, msg:緩沖區首地址, //len: 本次讀取,期望 寫入多少個字節的數據。 返回值:實際寫了多少字節數據}close(fd);return 0; }- 讀文件:
二、文件描述符
- 1.文件描述符和文件流指針的區別:
文件流指針:文件流指針是標準庫函數操作的句柄,類型為FILE*結構體類型。
文件描述符:文件描述符是系統調用的句柄,類型是int型,注意??,文件流指針中包含文件描述符
- 2.Linux進程默認情況下會有3個缺省打開的文件描述符,分別是標準輸入0,標準輸出1,標準錯誤2,所以輸入輸出可以采用下面 的方式
三、文件描述符的分配規則
- 1.文件描述符的管理
- 結合上圖:我們知道文件描述符都是從0開始的整數,當我們打開一個文件時,操作系統要在內存中創建相應的數據結構來管理描述目標文件。
- 于是就有了file結構體,表示已經打開的文件對象。
- 而進程執行open系統調用,所以必須讓進程和文件關聯起來。
- 描述進程的是進程控制塊PCB,Linux中是task_struct,內部除了描述進程相關信息外,還有一個指針*file,指向一張表file_struct,這張表最重要的部分是包含一個指針數組,數組中的每個元素都指向一個打開文件的指針,所以,本質上文件描述符就是該數組的下標,即只要拿到數組下標,取數組中的file指針就可以找到對應的文件,上面就是操作系統管理文件描述符的方式。
- 2.文件描述符的分配規則:
看下面的代碼:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() {int fd = open("myfile", O_RDONLY);if(fd < 0){perror("open");return 1;}printf("fd: %d\n", fd);close(fd);return 0; }
發現文件描述符fd為3。那么關閉0或者2再試試:
發現結果是0或者2,由此得出文件描述符的分配規則是:在file_struct結構體中,找當前沒有被使用的最小的下標,作為新的文件描述符
四、重定向
- 1.重定向:
先看代碼:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> int main() {close(1);int fd = open("myfile", O_WRONLY|O_CREAT, 00644);if(fd < 0){perror("open");return 1;}printf("fd: %d\n", fd);fflush(stdout);close(fd);exit(0); }- 此時,我們發現,本來應該輸出到顯示器上的內容,輸出到了文件 myfile 當中
- 因為一開始我們關閉了標準輸出文件描述符1,導致按照文件描述符的分配規則,fd就得到最小未使用的文件描述符,其代表數組的元素內容是指向myfile文件的,所以就輸出到myfile中,fd=1。
- 這種現象叫做輸出重定向。常見的重定向有:>(清空重定向), >>(追加重定向), <(標準輸入重定向)。
- 2.重定向的原理:
- 結合上圖,重定向的本質是重新定向文件描述符所在的file指針的指向,即改變以個文件描述符所對應的文件信息,進而改變操作的文件
- 注意??文件描述符重定向的過程中文件描述符的數量沒有發生改變,只是改變其數組內部file指針的指向而已。
五、dup2系統調用
int dup2(int oldfd, int newfd);作用是將newfd文件描述符的file指針指向oldfile文件描述符的file指針指向的文件。
看代碼:
#include <stdio.h> #include <unistd.h> #include <fcntl.h> int main() {int fd = open("myfile", O_CREAT | O_RDWR);if (fd < 0) {perror("open");return 1;}close(1);dup2(fd, 1);for (;;) {char buf[1024] = {0};ssize_t read_size = read(0, buf, sizeof(buf) - 1);if (read_size < 0) {perror("read");break;}printf("%s", buf);fflush(stdout);}return 0; }
說明使用dup2也可以改變文件描述符的指向(重定向)
六、minishell
#include <stdio.h> #include <sys/wait.h> #include <ctype.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h>char g_command[1024];//該函數的功能是獲取命令行輸入的數據 int GetCommand() {//因為開始獲得的內存中的內容是不定的,所以使用前要先初始化memset(g_command,'\0',sizeof(g_command));//這里需要為'\0'留一個位置,不能把g_command全部用來讀取內容,否者就沒有結束標志,容易發生內存訪問越界if(fgets(g_command,sizeof(g_command)-1,stdin)==NULL){printf("fgets is error!\n");return -1;}//printf("g_command:%s\n",g_command);return 0; }//解析字符串 char** DealCommand(char* command) {if(command==NULL&&*command=='\0'){printf("dealcommand is error\n");return NULL;}//用來保存命令static char* argv[1024]={0};int argc=0;while(*command){//isspace函數用來去掉多余的空格//isspace的返回值:如果當前字符是空格返回1,否則返回0//注意'\0'在issapce函數中不算空格的,所以要進行判斷while(!isspace(*command)&&*command!='\0'){argv[argc]=command;argc++;//去找下一個空格while(!isspace(*command)&&*command!='\0'){command++;}*command='\0';}command++;}argv[argc]=NULL;//for(int i=0;i<argc;i++)//{// printf("%d:%s ",i,argv[i]);//}//printf("\n");return argv; }//進行重定向 int redirect(char * g_command) {char* ptr = g_command;char* file = NULL;int fd ;//用來標記是清空重定向還是追加重定向int redirect_type = -1;while(*ptr !='\0'){//如果當前字符是 > ,把他置為'\0',并判斷下一個位置是否為'\0'if(*ptr == '>'){*ptr++ = '\0';redirect_type++;if(*ptr == '>'){*ptr++ = '\0';redirect_type++;}//去掉多余的空格while(isspace(*ptr)){ptr++;}//file就是空格后面的第一個字符串file = ptr;//繼續找空格,在這兩個空格之間就是文件的名稱while(!isspace(*ptr)&&*ptr != '\0'){ptr++;}*ptr='\0';//如果redirect_type==0說明是清空重定向,如果==1說明是追加重新定向if(redirect_type == 0){fd = open(file,O_CREAT|O_TRUNC|O_WRONLY,0664);}else{fd = open(file,O_CREAT|O_APPEND|O_WRONLY,0664);}dup2(fd,1);}ptr++;}return 0; }//進行程序替換 int exec() {redirect(g_command);char** argv=DealCommand(g_command);pid_t pid =fork();if(pid<0){printf("foek is error!\n");return -1;}else if(pid==0){//child//如果argc中為NULL,就直接返回if(argv[0]==NULL){exit(-1);}//進行替換,execvp第一個參數是可執行程序名,第二個參數是該可執行程序的參數組成的數組execvp(argv[0],argv);//execl("/usr/bin/ls","ls","-a",NULL);}else{//fatherwaitpid(pid,NULL,0);}return 0; }int main() {//循環讀數據while(1){printf("[dev@localhost dev]$ ");int ret = GetCommand();if(ret == -1){//如果讀取失敗,繼續循環讀取,不能直接break調continue;}//處理解析數據//char** argv = DealCommand(g_command);//進行替換//exec(argv);exec();}return 0; }總結
以上是生活随笔為你收集整理的Linux中的基础IO(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux中的基础IO(一)
- 下一篇: Linux中的信号