主頁 >  其他 > 13 Linux下的基礎IO

13 Linux下的基礎IO

2021-10-18 14:28:49 其他

不同作業系統所暴露出的介面是不同的,因此Linux下的一些系統呼叫介面是無法移植到Windows下的,


文章目錄

  • 一、C語言中的檔案介面
  • 二、系統檔案I/O
    • 2.1.系統呼叫介面
      • open
    • 2.2.檔案描述符fd(file descriptor)
    • 2.3.補充內容--函式指標訪問硬體
    • 2.4.重定向的實作原理
  • 三、FILE
  • 四、dup 重定向
    • 4.1.使用dup2 完成重定向
    • 4.2.重定向恢復
    • 4.3.在my_shell中添加重定向功能
  • 總結


一、C語言中的檔案介面

在C語言檔案操作時學過檔案介面C語言中的檔案介面

這里補充一些內容:

檔案=內容+屬性
stdin:標準輸入(鍵盤)
stdout:標準輸出(顯示幕)
stderr:標準錯誤(顯示幕)

Linux下一切皆檔案,所以stdin,stdout,stderr也是可以當做檔案看待,被fopen打開,
這是因為語言是人和計算機互動的載體,所以任何一門語言都需要標準輸入、輸出和錯誤

之所以能直接使用printf和scanf這種輸出到顯示幕和從鍵盤輸入的函式,是因為C語言默認幫助我們打開了這三個標準輸入和輸出的設備,

用下面的代碼驗證:
在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

可以看到普通檔案和顯示幕檔案在代碼層面上是沒有差別的,


二、系統檔案I/O

2.1.系統呼叫介面

操作檔案,除了上述C介面(當然,C++也有介面,其他語言也有),我們還可以采用系統介面來進行檔案訪問,使用man手冊可以查看他們:

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

fd:要打開檔案的描述符
buf:寫入/讀入的字串指標
count:寫入/讀入字符的個數(位元組數)

實際上,我們上面用的C語言檔案介面,在底層用的就是系統呼叫的介面
在這里插入圖片描述

系統呼叫的介面只有一套,和系統有關,而庫函式可以有多個(C語言檔案介面,C++檔案介面等),語言層的庫函式檔案介面都是基于系統呼叫介面進行的封裝,

由于顯示幕是硬體,硬碟也是硬體,所以任何語言的檔案操作最終都要通過作業系統進行對硬體的寫入,

open

通過mani手冊可以查看用法:

要包含的頭檔案:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

打開的檔案存在,使用下面的介面:
 int open(const char *pathname, int flags);
打開的檔案不存在,使用下面的介面:
 int open(const char *pathname, int flags, mode_t mode);

引數:
pathname:要打開檔案的名字

flags:打開檔案的方式
   O_RDONLY :只讀方式
   O_WRONLY :只寫方式
   O_RDWR :讀寫方式
可選項:
    O_TRUNC :截斷檔案(清空檔案內容)
    O_CREAT :檔案不存在則創建檔案
    O_APPEND :追加的方式
    O_EXCL | O_CREAT :如果檔案存在,則打開檔案失敗
    
mode:創建檔案時的權限(八進制,比如0664等)

回傳值:
成功:新打開的檔案描述符
失敗:-1

可選項的原理:
在這里插入圖片描述

所有選項對應的數在轉成二進制后只有一個位元位為1且為1的二進制位是不同的,所以傳多個選項的時候實際上是對傳入的數進行按位或處理,最后傳給flags的是一個數,這個數有一個或多個位元位為1,

以下面的代碼為例:

在這里插入圖片描述

在這里插入圖片描述

2.2.檔案描述符fd(file descriptor)

可以看到打開成功后各自的回傳值是3 4 5,,,
打開失敗回傳值則為-1
這些回傳值叫做檔案描述符,在系統層面是一個整數,從0開始,
其中:0為標準輸入,1為標準輸出,2為標準錯誤,這三個默認被打開

檔案描述符的本質是陣列下標,作業系統為每一個行程維護了一個檔案描述符表,該表的索引值都從從0開始的,索引值都有一個指標指向對應的檔案:

在這里插入圖片描述
在這里插入圖片描述

一個行程如何通過檔案描述符找到檔案:當行程執行write(4,"hello",5)時,行程先找到自己的PCB,PCB中包含檔案描述符表(struct files_struct),然后通過索引下標4找到對應的檔案,

所以如果將檔案描述符為0(標準輸入)的關掉,則分配的下標為0:
在這里插入圖片描述

在這里插入圖片描述

可以看出檔案描述符的分配規則為:在files_struct陣列當中,找到當前沒有被使用的最小的一個下標,作為新的檔案描述符,

另外,要記得關閉檔案描述符,否則會造成檔案描述符泄漏,因為檔案描述符表(陣列)是有上限的,

2.3.補充內容–函式指標訪問硬體

不同的硬體訪問方式是不一樣的,對于外設訪問的方式一般是讀和寫,但是實作代碼是不一樣的,此時行程就可以通過函式指標的方式來指向它們各自的實作方法:
在這里插入圖片描述
在這里插入圖片描述

2.4.重定向的實作原理

重定向有兩個運算子分別是>(格式化重定向)和>>(追加重定向),其實作原理就是作業系統內核把標準輸出(1)關掉,然后打開對應的檔案,此時該檔案的下標就是1,應用層默認輸入到下標為1的檔案中,所以就輸入到該檔案中了,至于追加重定向則是在打開的時候加上選項O_APPEND
在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述


三、FILE

檔案指標中那個FILE本質是一個結構體,這個結構體中一定是包含檔案描述符(fd)的,因為訪問檔案都是通過fd訪問的

對于下面的代碼:

#include<stdio.h>
#include<string.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
int main()
{
 const char *msg0="hello printf\n";
 const char *msg1="hello fwrite\n";
 const char *msg2="hello write\n";
 printf("%s", msg0);
 fwrite(msg1, strlen(msg0), 1, stdout);
 write(1, msg2, strlen(msg2));
 fork();
 return 0;
}

在這里插入圖片描述

如果對結果重定向,printffwrite(庫函式)都輸出了2次,而write只輸出了一次(系統呼叫),

這是因為重定向影響了緩沖方式
顯示幕采用的是行緩沖(遇到\n就重繪)
檔案采用的則是全緩沖(緩沖區資料寫滿才重繪)

沒有重定向之前是往顯示幕寫,而重定向則是往檔案中寫,

  • 一般C庫函式寫入檔案時是全緩沖的,而寫入顯示幕是行緩沖,
  • printf、fwrite庫函式會自帶緩沖區,當發生重定向到普通檔案時,資料的緩沖方式由行緩沖變成了全緩沖
  • 全緩沖行程退出之后,會統一重繪,寫入檔案當中,
  • fork的時候,父子資料會發生寫時拷貝,資料被暫存在緩沖區中,因此子行程也就有了同樣的一份資料,即產生兩份資料,
  • 由于父子行程的緩沖區中有兩份一樣的資料,所以會重繪兩份,
  • write 沒有重繪兩份,說明沒有所謂的緩沖區,

我們這里所說的緩沖區,都是用戶級緩沖區,printffwrite是庫函式, write是系統呼叫,庫函式在系統呼叫的“上層”, 是對系統呼叫的“封裝”,但是write沒有緩沖區,而 printffwrite有,足以說明,該緩沖區是二次加上的,由C標準庫提供,

另外fflush函式也在C標準庫中,將用戶級的緩沖區往系統中重繪:
在這里插入圖片描述

下面是FILE的代碼:
typedef struct _IO_FILE FILE; 在/usr/include/stdio.h

struct _IO_FILE {
 int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
 //緩沖區相關
 /* The following pointers correspond to the C++ streambuf protocol. */
 /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
 char* _IO_read_ptr; /* Current read pointer */
 char* _IO_read_end; /* End of get area. */
 char* _IO_read_base; /* Start of putback+get area. */
 char* _IO_write_base; /* Start of put area. */
  char* _IO_write_ptr; /* Current put pointer. */
 char* _IO_write_end; /* End of put area. */
 char* _IO_buf_base; /* Start of reserve area. */
 char* _IO_buf_end; /* End of reserve area. */
 /* The following fields are used to support backing up and undo. */
 char *_IO_save_base; /* Pointer to start of non-current get area. */
 char *_IO_backup_base; /* Pointer to first valid character of backup area */
 char *_IO_save_end; /* Pointer to end of non-current get area. */
 struct _IO_marker *_markers;
 struct _IO_FILE *_chain;
 int _fileno; //封裝的檔案描述符
#if 0
 int _blksize;
#else
 int _flags2;
#endif
 _IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */
 /* 1+column number of pbase(); 0 is unknown. */
 unsigned short _cur_column;
 signed char _vtable_offset;
 char _shortbuf[1];
 /* char* _save_gptr; char* _save_egptr; */
 _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

四、dup 重定向

上面的重定向是將標準輸出的fd關掉,然后打開重定向的檔案,
而使用dup2函式就不需要關掉標準輸出:
在這里插入圖片描述

dup函式的作用是,回傳一個新的檔案描述符(可用檔案描述符的最小值)newfd,并且新的檔案描述符newfd指向oldfd所指向的檔案表項,
比如:
在這里插入圖片描述

在這里插入圖片描述

檔案描述符為1的檔案通過dup重定向到檔案描述符1上,那么也就相當于檔案描述符3對應的檔案也是顯示幕檔案,那么向檔案描述符3進行write,最終結果也會列印在顯示幕上,

4.1.使用dup2 完成重定向

dup2有兩個引數oldfdnewfdnewfdoldfd的拷貝,將newfd重定向到oldfd,當整個函式呼叫成功后,會將newfd關掉,然后讓newfd指向oldfd,總之,dup2函式的作用就是讓newfd重定向到oldfd所指的檔案表項上,如果出錯就回傳-1,否則回傳的就是newfd,所以如果想讓原本輸出到顯示幕上的資料重定向到檔案中,可以這樣寫:
在這里插入圖片描述

在這里插入圖片描述

4.2.重定向恢復

在進行重定向后,如果想要恢復到重定向之前的狀態,可以在重定向之前用dup函式保留該檔案描述符對應的檔案表項,然后在需要恢復重定向的時候使用dup2重定向到原來的檔案表項,以重定向后恢復標準輸出為例,如下所示:

在這里插入圖片描述

在這里插入圖片描述

4.3.在my_shell中添加重定向功能

其實作原理是在子行程進行程式替換之前將標準輸出(1)重定向到打開的檔案中,

#include<stdio.h>              
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<ctype.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define SIZE 256
#define NUM 16 //命令列引數的個數

void redirect(char* cmd)
{
  int fd=-1;
  int redirect_count=0;//記錄>的個數
  char*file=NULL;
  char*ptr=cmd;
  while(*ptr)
  {
    if(*ptr=='>')
    {
      *ptr++='\0';
      redirect_count++;
      if(*ptr=='>')
      {
        *ptr++='\0';
        redirect_count++;
      }
      while(*ptr!='\0'&&isspace(*ptr))//跳過空格
      {
        ptr++;
      }
      file=ptr;//找到檔案名
      while(*ptr!='\0'&&!isspace(*ptr))//清空檔案名后面的空格
      {
        ptr++;
      }
      *ptr='\0';
      
      if(redirect_count==1){
        //>
        fd=open(file,O_CREAT|O_TRUNC|O_WRONLY,0644);
      }
      else if(redirect_count==2){
        //>>
        fd=open(file,O_CREAT|O_APPEND|O_WRONLY,0644);   
      }
      else{
        //do nothing!
      }
      //檔案已經打開,用dup2重定向
      dup2(fd,1);
      close(fd);
    }//end if
    else if(*ptr=='<')
   { 
      //和重定向>類似
   }
    ptr++;
  }
  
}
int main()                                                                    
{
  char cmd[SIZE];
  const char* cmd_line="[my_shell@VM-0-16-centos ~]# ";
  while(1)
  {
    cmd[0]=0;

    printf("%s",cmd_line);
    fgets(cmd,SIZE,stdin);
    cmd[strlen(cmd)-1]='\0'; 
    pid_t id=fork();
    if(id<0)
    {
      perror("fork error!\n");
      continue;
    }
    if(id==0)//子行程
    {
      redirect(cmd);
      char*args[NUM];//將命令字串分割
      args[0]=strtok(cmd," ");
      int i=1;
	    do    
	    {    
	      args[i]=strtok(NULL," ");    
	      if(args[i]==NULL)    
	      {    
	        break;    
	      }    
	      i++;    
	    }while(1);   
     execvp(args[0],args);
     exit(1);
     }
    int status=0;
    pid_t ret=waitpid(id,&status,0);
    if(ret>0)
    {
      printf("status code:%d\n",(status>>8)&0xFF);
    }
  }
  return 0;
} 

在這里插入圖片描述


總結

  1. 作業系統提供系統呼叫介面(open,close,read,write),C語言對系統呼叫介面進行封裝
  2. FILE*是個結構體指標,FILE是個結構體,有兩個比較重要的方面:檔案描述符和緩沖區(C語言提供)
  3. fd是系統呼叫,fd是檔案描述符表(陣列)的下標,里面的內容是檔案指標指向檔案,系統默認打開0 1 2(標準輸入,標準輸出,標準錯誤)
  4. 重定向的底層是將fd的指向改變

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/321239.html

標籤:其他

上一篇:資料結構初階:演算法復雜度

下一篇:身價過億的帝都富豪對小碼農說順序表會了嗎

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more