国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Linux文件理解和系統(tǒng)調(diào)用

這篇具有很好參考價(jià)值的文章主要介紹了Linux文件理解和系統(tǒng)調(diào)用。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

Linux文件理解和系統(tǒng)調(diào)用

本文已收錄至《Linux知識(shí)與編程》專欄!
作者:ARMCSKGT
演示環(huán)境:CentOS 7

Linux文件理解和系統(tǒng)調(diào)用


前言

我們?cè)趯W(xué)習(xí)C語(yǔ)言時(shí)可以使用fopen打開(kāi)文件fclose關(guān)閉文件;那么是C語(yǔ)言幫我們打開(kāi)的文件嗎?其實(shí)并不是,語(yǔ)言沒(méi)有這個(gè)能力,而是借助操作系統(tǒng)之手打開(kāi)文件并進(jìn)行操作,本篇將為大家介紹關(guān)于Linux下文件操作的系統(tǒng)調(diào)用,并介紹Linux系統(tǒng)如何組織和管理進(jìn)程打開(kāi)的文件!
Linux文件理解和系統(tǒng)調(diào)用


正文

在對(duì)文件操作之前,我們需要知道文件在系統(tǒng)中到底是什么!

文件概念


  • 文件操作本質(zhì):我們從語(yǔ)言層面是使用庫(kù)函數(shù)操作文件,讓我們以外文件操作是語(yǔ)言承擔(dān);但其實(shí)并非如此,文件操作是操作系統(tǒng)的事,是系統(tǒng)層面的問(wèn)題,操作系統(tǒng)對(duì)于打開(kāi)文件也會(huì)像管理進(jìn)程一樣通過(guò)先描述再組織進(jìn)行管理
  • 幾乎所有語(yǔ)言都有文件操作,但是操作方法不太相同,但都是對(duì)系統(tǒng)接口的封裝,不同的語(yǔ)言有不同的范式,所以使用上會(huì)有區(qū)別,底層調(diào)用的是同一個(gè)系統(tǒng)調(diào)用
  • 操作文件的第一件事就是打開(kāi)文件,而 文件=內(nèi)容+屬性 ,針對(duì)文件的操作有對(duì)文件內(nèi)容的操作,也有對(duì)文件屬性的操作;當(dāng)文件沒(méi)有被操作的時(shí)候,文件一般在磁盤(外存)上;當(dāng)我們對(duì)文件進(jìn)行操作的時(shí)候,文件需要被加載到內(nèi)存中,因?yàn)轳T諾依曼體系結(jié)構(gòu),CPU要讀文件需要先把文件搬到內(nèi)存
  • 當(dāng)我們對(duì)文件進(jìn)行操作的時(shí)候,文件需要提前被加載到內(nèi)存,至少需要把文件屬性加載到內(nèi)存中;而每分每秒不止一個(gè)文件被加載到內(nèi)存(不止一個(gè)文件被打開(kāi)),也可能不止一個(gè)用戶在加載文件到內(nèi)存,內(nèi)存中一定存在大量的不同文件的屬性
  • 打開(kāi)文件本質(zhì)就是將我們需要的文件屬性加載到內(nèi)存中;操作系統(tǒng)內(nèi)部一定會(huì)存在大量的被打開(kāi)的文件,操作系統(tǒng)要管理這些被打開(kāi)的文件,管理方式是:先描述再組織

    所以:每一個(gè)被打開(kāi)的文件都要在操作系統(tǒng)內(nèi)對(duì)應(yīng)文件對(duì)象的struct file對(duì)象,可以將所有的struct file對(duì)象用某種數(shù)據(jù)結(jié)構(gòu)鏈接起來(lái),在操作系統(tǒng)內(nèi)部對(duì)被打開(kāi)的文件進(jìn)行管理就被轉(zhuǎn)換成為了對(duì)數(shù)據(jù)結(jié)構(gòu)的增刪查改

    描述: 構(gòu)建在內(nèi)存中的文件結(jié)構(gòu)體,也就是創(chuàng)建 struct file 對(duì)象記錄被打開(kāi)的文件的屬性信息
    組織: 通過(guò)struct file類型對(duì)象指針形成鏈表(等其他數(shù)據(jù)結(jié)構(gòu)),對(duì)文件的管理就變成了對(duì)數(shù)據(jù)結(jié)構(gòu)的增刪查改
  • 文件其實(shí)可以被分成兩大類:磁盤文件和被打開(kāi)的文件(內(nèi)存文件)
  • 文件被打開(kāi),是操作系統(tǒng)在打開(kāi),是用戶讓操作系統(tǒng)打開(kāi)的,用戶是以進(jìn)程(bash)為代表的;我們之前的所有的文件操作,都是 進(jìn)程被打開(kāi)文件 的關(guān)系;

    進(jìn)程被打開(kāi)文件 的關(guān)系:struct task_struct 和 struct file 之間的聯(lián)系

結(jié)論:真正的文件操作是需要通過(guò)系統(tǒng)調(diào)用實(shí)現(xiàn),而我們之前的文件操作都是進(jìn)程操作系統(tǒng)間的交互;文件被打開(kāi),操作系統(tǒng)要為被打開(kāi)的文件,創(chuàng)建對(duì)應(yīng)的內(nèi)核數(shù)據(jù)結(jié)構(gòu)struct file,其中包含各種屬性和各種鏈接關(guān)系!


文件描述符


文件描述符概念

在C語(yǔ)言中,我們打開(kāi)一個(gè)文件會(huì)形成一個(gè)FILE類型的指針,fopen打開(kāi)文件會(huì)傳遞一個(gè)FILE類型的對(duì)象地址(底層創(chuàng)建了一個(gè)FILE對(duì)象)供我們使用,我們操作不同的文件圍繞不同的FILE指針即可!

#include <stdio.h>

int main()
{
   FILE* f1 = fopen("test1.txt", "r");
   FILE* f2 = fopen("test2.txt", "w");

   //讀取寫(xiě)入操作

   fclose(f1);
   fclose(f2);
   f1 = f2 = NULL;
   
   return 0;
}

代碼中,我們要操作不同的文件只需要對(duì)f1和f2指針進(jìn)行操作即可,但是FILE是一個(gè)對(duì)象,而底層是對(duì)文件描述符和其他屬性進(jìn)行封裝,在操作系統(tǒng)層面上,對(duì)任何文件操作只認(rèn)該進(jìn)程的文件描述符!

FILE對(duì)象
這里分享FILE對(duì)象源碼,F(xiàn)ILE對(duì)象是_IO_FILE的重命名,_IO_FILE對(duì)象中 _fileno 就是文件描述符!

typedef struct _IO_FILE FILE; //stdio庫(kù)中對(duì)_IO_FILE類型重命名為FILE

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
};

打印文件描述符
我們嘗試打印文件描述符,首先我們知道,C語(yǔ)言有三個(gè)默認(rèn)的流:

  • sdtin標(biāo)準(zhǔn)輸入流(我們從鍵盤輸入的文件流)
  • stdout標(biāo)準(zhǔn)輸出流(打印到屏幕的流)
  • stderr標(biāo)準(zhǔn)錯(cuò)誤輸出流

    這三個(gè)流都是FILE類型我們通過(guò)以下C++代碼輸出標(biāo)準(zhǔn)流的類型與普通文件流做對(duì)比:
#include <iostream>
#include <cstdio>
#include <typeinfo> //typeid所需庫(kù)
using namespace std;
int main()
{
   FILE* f1 = fopen("./test1.txt", "r");
   FILE* f2 = fopen("./test2.txt", "w");
   
   cout<<"類型對(duì)比:"<<endl;
   cout<<"f1指針類型:"<<typeid(f1).name()<<endl;
   cout<<"stdin指針類型:"<<typeid(stdin).name()<<endl;
   cout<<endl;
   cout<<"文件描述符"<<endl;
   cout<<"stdin文件描述符:"<<stdin->_fileno<<endl;
   cout<<"stdout文件描述符:"<<stdout->_fileno<<endl;
   cout<<"stderr文件描述符:"<<stderr->_fileno<<endl;
   cout<<"f1文件描述符:"<<f1->_fileno<<endl;
   cout<<"f2文件描述符:"<<f2->_fileno<<endl;

   fclose(f1);
   fclose(f2);
   f1 = f2 = NULL;
   
   return 0;
}

Linux文件理解和系統(tǒng)調(diào)用
從這里可以看出文件描述符是真實(shí)存在的,且是一個(gè)整數(shù)從0開(kāi)始,而我們自己打開(kāi)一個(gè)文件的文件描述符是從3開(kāi)始的!


文件管理

操作系統(tǒng)要對(duì)這些打開(kāi)的文件進(jìn)行管理,否則每次操作文件都需要去內(nèi)存中查找,高效的管理可以極大的提高IO效率!

對(duì)于打開(kāi)的文件,操作系統(tǒng)會(huì)以先描述再組織的形式管理這些被打開(kāi)的文件!

操作系統(tǒng)將這些打開(kāi)的文件視為file對(duì)象,通過(guò)他們的file指針操作,并將這些file指針存入數(shù)組中,使用數(shù)組下標(biāo)進(jìn)行管理,這個(gè)數(shù)組為 file* fd_array[] ,而數(shù)組的下標(biāo)就是神秘的文件描述符fd

除了文件描述符外,文件的屬性還有文件權(quán)限、大小、路徑、引用計(jì)數(shù)、掛載數(shù)等信息,將這些文件屬性信息匯集起來(lái)就構(gòu)成了 struct files_struct 這個(gè)結(jié)構(gòu)體,它正是進(jìn)程控制塊 struct task_struct 中的成員之一!

而當(dāng)一個(gè)程序啟動(dòng)時(shí),操作系統(tǒng)會(huì)默認(rèn)為他打開(kāi) stdin標(biāo)準(zhǔn)輸入流 , stdout標(biāo)準(zhǔn)輸出流 , stderr標(biāo)準(zhǔn)錯(cuò)誤流 這三個(gè)文件流,將他們的文件file指針存入 fd_array[] 數(shù)組中,依次為 0,1,2 三個(gè)數(shù)組下標(biāo),也就是文件描述符;后續(xù)再打開(kāi)文件時(shí),默認(rèn)將打開(kāi)的文件file指針?lè)峙涞疆?dāng)前數(shù)組未使用的最小下標(biāo)處,所以用戶打開(kāi)文件一般是從3開(kāi)始的,當(dāng)然我們關(guān)閉所有標(biāo)準(zhǔn)流后打開(kāi)文件就是從0開(kāi)始分配文件描述符!


關(guān)于 files_struct

當(dāng)我們打開(kāi)一個(gè)文件時(shí),在內(nèi)存中會(huì)形成一個(gè)files_struct對(duì)象,files_struct對(duì)象是對(duì)該文件屬性的描述!
Linux文件理解和系統(tǒng)調(diào)用
針對(duì)每個(gè)進(jìn)程都會(huì)打開(kāi)文件,進(jìn)程控制塊task_struct中必然包含文件操作相關(guān)信息,也就是files_struct !

注意:當(dāng)我們沒(méi)有被打開(kāi)時(shí),文件在磁盤上;當(dāng)文件被打開(kāi)后,并不是直接將全部?jī)?nèi)容加載到內(nèi)存上,而是先通過(guò)文件inode(后面介紹)找到磁盤上文件的詳細(xì)信息,加載文件屬性信息形成files_struct,待使用時(shí)再加載內(nèi)容!


文件描述符的分配

文件描述符fd的分配規(guī)則是:分配到當(dāng)前描述符數(shù)組未使用的最小下標(biāo)位置處!

說(shuō)明:

  • 當(dāng)我們打開(kāi)文件時(shí),因?yàn)槟J(rèn)的三個(gè)標(biāo)準(zhǔn)文件流已經(jīng)打開(kāi),所以當(dāng)前的最小下標(biāo)一定是3
  • 如果我們關(guān)閉了標(biāo)準(zhǔn)文件流,例如stdin(文件描述符為0),則新打開(kāi)的文件會(huì)分配文件描述符0(未使用的最小下標(biāo)處)
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
   cout<<"stdin文件描述符:"<<stdin->_fileno<<endl;
   cout<<"stdout文件描述符:"<<stdout->_fileno<<endl;
   cout<<"stderr文件描述符:"<<stderr->_fileno<<endl;

   FILE* f1 = fopen("./test1.txt", "r"); //先打開(kāi)test1文件
   cout<<"f1文件描述符:"<<f1->_fileno<<endl;

   cout<<"關(guān)閉stdin標(biāo)準(zhǔn)文件流"<<endl; //關(guān)閉stdin
   fclose(stdin);

   FILE* f2 = fopen("./test2.txt", "w"); //再打開(kāi)test2文件
   cout<<"f2文件描述符:"<<f2->_fileno<<endl;

   fclose(f1);
   fclose(f2);
   f1 = f2 = NULL;
   
   return 0;
}

Linux文件理解和系統(tǒng)調(diào)用


一切皆文件思想

我們知道在Linux系統(tǒng)下一切皆文件,我們?nèi)绾卫斫膺@個(gè)概念?

對(duì)于Linux系統(tǒng)來(lái)說(shuō),無(wú)論是鍵盤還是顯示器等設(shè)備,在他開(kāi)來(lái)都是文件,是一個(gè)file對(duì)象

無(wú)論是硬件外設(shè)還是軟件,對(duì)于操作系統(tǒng)來(lái)說(shuō)無(wú)非就是輸入和輸出兩個(gè)操作,所以操作系統(tǒng)對(duì)于這些硬件只需要提供讀方法和寫(xiě)方法即可驅(qū)動(dòng)該硬件(對(duì)于只讀或只寫(xiě)的設(shè)備屏蔽其中一個(gè)方法即可),所以這些硬件設(shè)備被當(dāng)成文件打開(kāi),在程序啟動(dòng)時(shí)將他們的file寫(xiě)入fd_array中管理即可,所以Linux下一切皆文件!
Linux文件理解和系統(tǒng)調(diào)用


C語(yǔ)言文件操作


在講解系統(tǒng)調(diào)用前,我們簡(jiǎn)單了解一下C庫(kù)的文件操作方式!
如果想要詳細(xì)的了解,請(qǐng)閱讀官方文檔:C文件操作庫(kù)

文件的打開(kāi)與關(guān)閉

文件的打開(kāi)使用fopen,關(guān)閉使用fclose!

打開(kāi)文件:

FILE * fopen ( const char * filename, const char * mode ); //打開(kāi)文件
  • 參數(shù):
    – filename:被打開(kāi)文件的本地路徑
    – mode:打開(kāi)方式(以字符串的方式傳遞)
  • 返回值:
    –如果文件不存在則返回空指針
文件打開(kāi)方式 含義 如果指定文件不存在
“r”(只讀) 為了輸入數(shù)據(jù),打開(kāi)一個(gè)已經(jīng)存在的文本文件 出錯(cuò)
“w”(只寫(xiě)) 為了輸出數(shù)據(jù),打開(kāi)一個(gè)文本文件 建立一個(gè)新的文件
“a”(追加) 向文本文件尾添加數(shù)據(jù) 建立一個(gè)新的文件
“rb”(只讀) 為了輸入數(shù)據(jù),打開(kāi)一個(gè)二進(jìn)制文件 出錯(cuò)
“wb”(只寫(xiě)) 為了輸出數(shù)據(jù),打開(kāi)一個(gè)二進(jìn)制文件 建立一個(gè)新的文件
“ab”(追加) 向一個(gè)二進(jìn)制文件尾添加數(shù)據(jù) 出錯(cuò)
“r+”(讀寫(xiě)) 為了讀和寫(xiě),打開(kāi)一個(gè)文本文件 出錯(cuò)
“w+”(讀寫(xiě)) 為了讀和寫(xiě),建議一個(gè)新的文件 建立一個(gè)新的文件
“a+”(讀寫(xiě)) 打開(kāi)一個(gè)文件,在文件尾進(jìn)行讀寫(xiě) 建立一個(gè)新的文件
“rb+”(讀寫(xiě)) 為了讀和寫(xiě)打開(kāi)一個(gè)二進(jìn)制文件 出錯(cuò)
“wb+”(讀寫(xiě)) 為了讀和寫(xiě),新建一個(gè)新的二進(jìn)制文件 建立一個(gè)新的文件
“ab+”(讀寫(xiě)) 打開(kāi)一個(gè)二進(jìn)制文件,在文件尾進(jìn)行讀和寫(xiě) 建立一個(gè)新的文件

關(guān)閉文件:

int fclose ( FILE * stream );
  • 參數(shù):
    –stream:FILE文件指針
  • 返回值:
    –成功返回0,失敗返回EOF(-1)

演示:

#include <stdio.h>
int main()
{
   FILE* f1 = fopen("./test1.txt", "r");
   FILE* f2 = fopen("./test2.txt", "w");
   if(f1 && f2) printf("文件打開(kāi)成功!\n"); //不是空指針則打開(kāi)成功

   int m = fclose(f1);
   int n = fclose(f2);
   if(!m && !n) printf("文件關(guān)閉成功!\n"); //返回0則關(guān)閉成功
   f1 = f2 = NULL;
   return 0;
}

Linux文件理解和系統(tǒng)調(diào)用


文件讀寫(xiě)

文件讀寫(xiě)結(jié)果配套出現(xiàn),有讀就有寫(xiě)!

文件讀取接口:

//讀取文件中的一個(gè)字符
int fgetc ( FILE * stream ); 

//讀取文件中一行字符
char * fgets ( char * str, int num, FILE * stream ); 

//從給定流 stream 讀取數(shù)據(jù)到 ptr所指向的數(shù)組中
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

//從一個(gè)流中執(zhí)行格式化輸入,遇到空格和換行時(shí)結(jié)束
int fscanf ( FILE * stream, const char * format, ... );

//從字符串讀取格式化輸入,遇到空格和換行時(shí)結(jié)束
int sscanf ( const char * s, const char * format, ...);

文件寫(xiě)入接口:

//將字符character寫(xiě)入文件中
int fputc ( int character, FILE * stream );

//將字符串str寫(xiě)入文件中
int fputs ( const char * str, FILE * stream );

//把 ptr 所指向的數(shù)組中的數(shù)據(jù)寫(xiě)入到給定流 stream 中
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

//將字符串格式化輸出到流 stream 中
int fprintf(FILE *stream, const char *format, ...);

其他寫(xiě)入接口:

//將字符串格式化寫(xiě)入str中
int sprintf(char *str, const char *format, ...);

//向s字符串格式化寫(xiě)入n個(gè)字符
int snprintf ( char * s, size_t n, const char * format, ... );

snprintf是sprintf的升級(jí)版,可以控制寫(xiě)入字符數(shù)量,更加安全;在文件操作中,這兩個(gè)接口常用于向緩沖區(qū)中寫(xiě)入數(shù)據(jù),然后整體寫(xiě)入到文件中(為了更加方便合理的向文件中寫(xiě)入數(shù)據(jù),一般預(yù)先定義緩沖區(qū)存儲(chǔ)數(shù)據(jù)然后整體寫(xiě)入)!

示例:
這里我們使用fscanf格式化讀取文件,snprintf格式化寫(xiě)入緩沖區(qū),fprintf格式化寫(xiě)入到文件!

#include <stdio.h>
#include <stdlib.h>
#define FNAME "log" //操作文件名

int main()
{
   //寫(xiě)操作
   FILE* wfp = fopen(FNAME,"w+"); //以只寫(xiě)的方式打開(kāi)log文件,如果沒(méi)有則創(chuàng)建
   if(!wfp) //打開(kāi)失敗就退出
   {
       perror("fopen error!\n");
       exit(EOF);
   }
   char buf1[64] = {0}; //寫(xiě)入緩沖區(qū)
   snprintf ( buf1, sizeof(buf1), "%s:%d", "向文件寫(xiě)入",668 ); //先格式化寫(xiě)入緩沖區(qū)
   fprintf(wfp,"%s",buf1); //將緩沖區(qū)中的字符串整體寫(xiě)入文件中
   fclose(wfp); //寫(xiě)操作完成后關(guān)閉文件
   wfp = NULL;

   //讀操作
   FILE* rfp = fopen(FNAME,"r"); //以只讀的方式打開(kāi)log文件
   if(!rfp) //打開(kāi)失敗就退出
   {
       perror("fopen error!\n");
       exit(EOF);
   }
   char buf2[64] = {0}; //讀取緩沖區(qū)
   fscanf(rfp,"%s",buf2);
   printf("%s\n",buf2);
   fclose(rfp); //讀操作完成后關(guān)閉文件
   rfp=NULL;

   return 0;
}

Linux文件理解和系統(tǒng)調(diào)用
注意:我們?cè)趯?xiě)入字符串時(shí)沒(méi)有加入 \n 換行,因?yàn)?\n 是C語(yǔ)言定義的換行符,其他語(yǔ)言和軟件可能無(wú)法識(shí)別,所以我們寫(xiě)入時(shí)建議不要帶有一些僅語(yǔ)言定義的格式符;當(dāng)我們使用cat打印出log文件中的信息時(shí),輸出了與我們文件操作一模一樣的字符只不過(guò)沒(méi)有換行!


文件操作系統(tǒng)調(diào)用


前面簡(jiǎn)單介紹了C語(yǔ)言的文件操作,現(xiàn)在我們來(lái)介紹Linux文件操作系統(tǒng)調(diào)用!

打開(kāi)文件open

打開(kāi)文件使用open接口,關(guān)于open接口:

#include <sys/types.h> //open接口所需庫(kù)
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags); 
int open(const char *pathname, int flags, mode_t mode); //打開(kāi)文件可以修改權(quán)限
  • 返回值:
    –如果文件打開(kāi)成功則返回對(duì)應(yīng)的文件描述符,如果打開(kāi)失敗則返回-1
  • 參數(shù):
    –pathname:被打開(kāi)文件的路徑(與C語(yǔ)言保持一致)
    –flags:打開(kāi)方式,使用的標(biāo)記位的方式傳遞選項(xiàng)信號(hào)(標(biāo)記位以位圖方式設(shè)置)
    –mode:如果文件不存在,創(chuàng)建文件時(shí)的權(quán)限設(shè)置,文件起始權(quán)限為0666
  • 注意:
    這兩個(gè)open函數(shù)類似于重載,如果我們打開(kāi)的文件可能不存在,則一定要手動(dòng)設(shè)置mode權(quán)限,否則文件創(chuàng)建出來(lái)權(quán)限是隨機(jī)值組成的,這樣可以保證文件安全;繼承環(huán)境變量表后,umask 默認(rèn)為 0002,當(dāng)然也可以使用umask函數(shù)自定義!

關(guān)于設(shè)置標(biāo)志位flags的理解:
我們知道一個(gè)int有四字節(jié),一共32個(gè)比特位,每一個(gè)比特位可以表示1/0
Linux文件理解和系統(tǒng)調(diào)用
而在open函數(shù)的flags函數(shù)中,我們可以想想為有32個(gè)開(kāi)關(guān),進(jìn)行不同的組合,不能有相同的組合和包含某一個(gè)組合,這樣某一個(gè)標(biāo)志位都是獨(dú)立的,表示一個(gè)指令信息!
如果我們要驗(yàn)證某一個(gè)標(biāo)志位是否滿足使用按位與即可,如果我們要融合多個(gè)標(biāo)志位指令一起傳遞給函數(shù)使用按位或即可!

利用這個(gè)特性,我們可以實(shí)現(xiàn)一個(gè)小的位圖deom:

#include <stdio.h>

#define ONE 0x1 //定義位圖標(biāo)志位(比特位不能包含和相同)
#define TWO 0x2
#define THREE 0x4

void directives(int flags)
{
   //模擬實(shí)現(xiàn)三種選項(xiàng)指令傳遞
   if(flags & ONE)
       printf("ONE指令\n");

   if(flags & TWO)
       printf("TWO指令\n");

   if(flags & THREE)
       printf("THREE指令\n");
}

int main()
{
   //使用按位或傳遞多個(gè)標(biāo)志位參數(shù)
   directives(ONE);
   printf("**************************\n");
   directives(ONE | TWO);
   printf("**************************\n");
   directives(ONE | TWO | THREE);

   return 0;
}

Linux文件理解和系統(tǒng)調(diào)用

關(guān)于flags常用的標(biāo)志位:

O_RDONLY	//只讀
O_WRONLY	//只寫(xiě)
O_APPEND	//追加
O_CREAT		//新建
O_TRUNC		//清空
O_RDRW		//可讀可寫(xiě)
O_EXCL		//文件必須是被創(chuàng)建的,如果文件已存在則報(bào)錯(cuò)-1

這些標(biāo)志位可以通過(guò)按位或進(jìn)行組合!

基于C語(yǔ)言打開(kāi)方式的常用組合:

  • w:O_WRONLY | O_CREAT | O_TRUNC (如果文件不存在則創(chuàng)建并清空文件內(nèi)容,只寫(xiě))
  • a:O_WRONLY | O_CREAT | O_APPEND (如果文件不存在則創(chuàng)建,只追加寫(xiě)入)
  • r:O_RDONLY (以只讀的方式打開(kāi)文件)
  • …還有一些其他功能,根據(jù)標(biāo)志位進(jìn)行自由組合即可!

所以只要我們想使用open做到只寫(xiě)方式打開(kāi)不存在的文件,也不會(huì)報(bào)錯(cuò),加個(gè) O_CREAT 參數(shù)即可實(shí)現(xiàn)自動(dòng)創(chuàng)建!


關(guān)閉文件close

系統(tǒng)調(diào)用關(guān)閉文件使用close函數(shù),與fclose相似!

#include <unistd.h>
int close(int fildes); //fildes(fd)是文件描述符

close函數(shù)解析:

  • 參數(shù)fildes:需要關(guān)閉文件的文件描述符
  • 返回值:關(guān)閉成功返回0,失敗返回-1

我們可以通過(guò)close(0),close(1),close(2)方式關(guān)閉標(biāo)準(zhǔn)文件流stdin,stdout,stderr!


寫(xiě)入文件write

write函數(shù)用于寫(xiě)入文件,其返回值類型有點(diǎn)特殊,但使用方法與fwrite基本一致!

#include <unistd.h>
ssize_t write(int fildes, const void *buf, size_t count);

write函數(shù)解析:

  • 參數(shù):
    – fildes:文件描述符
    – buf:寫(xiě)入的字符串目標(biāo)源指針或緩沖區(qū)(簡(jiǎn)稱寫(xiě)入源)
    – count:寫(xiě)入的字節(jié)數(shù)
  • 返回值:寫(xiě)入成功返回寫(xiě)入的字節(jié)數(shù),失敗返回-1

讀取文件read

系統(tǒng)調(diào)用read用于從文件中讀取指定字節(jié)的數(shù)據(jù)!

#include <unistd.h>
ssize_t read(int fildes, void *buf, size_t count);

read函數(shù)解析:

  • 參數(shù):
    – fildes:文件描述符
    – buf:讀入的緩沖區(qū)(將讀入數(shù)據(jù)寫(xiě)入到buf緩沖區(qū),可以是一個(gè)字符數(shù)組或開(kāi)辟的空間)
    – count:讀入的字節(jié)數(shù)
  • 返回值:讀取成功返回讀入的字節(jié)數(shù),讀取失敗返回-1

系統(tǒng)調(diào)用演示

注意:雖然我們使用系統(tǒng)調(diào)用寫(xiě)入數(shù)據(jù),但是為了方便,我們?cè)趯?xiě)入和讀取時(shí)還是借助緩沖區(qū)buf比較好!

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FNAME "log" //操作文件名

int main()
{
	//以只寫(xiě)的方式打開(kāi)文件,>如果不存在則創(chuàng)建且清空文件內(nèi)容
   int wfd = open(FNAME,O_WRONLY | O_CREAT | O_TRUNC,0664);
   assert(wfd>0); //檢測(cè)是否打開(kāi)成功
   char buf1[64] = {0}; //寫(xiě)入緩沖區(qū)
   snprintf ( buf1, sizeof(buf1), "%s:%d", "向文件寫(xiě)入",668 ); //先格式化寫(xiě)入緩沖區(qū)
   int wsize = write(wfd,buf1,sizeof(buf1)); //寫(xiě)入緩沖區(qū)大小的內(nèi)容
   printf("寫(xiě)入%d字節(jié)\n",wsize);
   close(wfd); //關(guān)閉文件

	//以只讀的方式打開(kāi)文件
   int rfd = open(FNAME,O_RDONLY); 
   assert(rfd>0); //檢測(cè)是否打開(kāi)成功
   char buf2[64] = {0}; //寫(xiě)入緩沖區(qū)
   int rsize = read(rfd,buf2,sizeof(buf2)); //向緩沖區(qū)buf2讀入文件中緩沖區(qū)大小的內(nèi)容
   printf("讀取%d字節(jié)\n",rsize);
   close(rfd); //關(guān)閉文件
   printf("讀入內(nèi)容: %s\n",buf2);
   return 0;
}

Linux文件理解和系統(tǒng)調(diào)用
同樣的,我們cat打開(kāi)文件沒(méi)有換行的問(wèn)題我們?cè)谇懊鍯語(yǔ)言已經(jīng)介紹了;不過(guò)需要注意的是,通過(guò)系統(tǒng)級(jí)函數(shù) write 寫(xiě)入字符串時(shí),不要刻意加上 ‘\0’,因?yàn)閷?duì)于系統(tǒng)來(lái)說(shuō),這也只是一個(gè)普通的字符(‘\0’ 作為字符串結(jié)尾也是C語(yǔ)言的規(guī)定)與 \n 的問(wèn)題一樣!


最后

Linux文件操作系統(tǒng)調(diào)用到這里就介紹的差不多了,本節(jié)我們介紹了Linux下關(guān)于文件操作的系統(tǒng)調(diào)用,了解了操作系統(tǒng)管理被打開(kāi)文件使用文件描述符的概念,知道了語(yǔ)言庫(kù)函數(shù)底層是對(duì)系統(tǒng)調(diào)用的封裝,以及Linux下一切皆文件思想的依據(jù)等等,文件的學(xué)習(xí)還沒(méi)結(jié)束,下一節(jié)我們繼續(xù)探究通過(guò)文件描述符如何實(shí)現(xiàn)重定向功能!

本次 <Linux文件理解和系統(tǒng)調(diào)用> 就先介紹到這里啦,希望能夠盡可能幫助到大家。

如果文章中有瑕疵,還請(qǐng)各位大佬細(xì)心點(diǎn)評(píng)和留言,我將立即修補(bǔ)錯(cuò)誤,謝謝!
Linux文件理解和系統(tǒng)調(diào)用

文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-476707.html

??其他文章閱讀推薦??
Linux<進(jìn)程控制> -CSDN博客
Linux<進(jìn)程地址空間> -CSDN博客
Linux<環(huán)境變量> -CSDN博客
Linux<進(jìn)程初識(shí)> -CSDN博客
Linux<進(jìn)程狀態(tài)及優(yōu)先級(jí)> -CSDN博客
??歡迎讀者多多瀏覽多多支持!??

到了這里,關(guān)于Linux文件理解和系統(tǒng)調(diào)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • linux的文件系統(tǒng),理解一切皆文件

    linux的文件系統(tǒng),理解一切皆文件

    open 函數(shù)具體使用哪個(gè),和具體應(yīng)用場(chǎng)景相關(guān),如目標(biāo)文件不存在,需要open創(chuàng)建,則第三個(gè)參數(shù)表示創(chuàng)建文件 的默認(rèn)權(quán)限,否則,使用兩個(gè)參數(shù)的open。 fopen fclose fread fwrite 都是C標(biāo)準(zhǔn)庫(kù)當(dāng)中的函數(shù),我們稱之為庫(kù)函數(shù)(libc)。 open close read write lseek 都屬于系統(tǒng)提供的接口,稱之

    2024年02月10日
    瀏覽(43)
  • 【Linux】帶你深入理解文件系統(tǒng)

    【Linux】帶你深入理解文件系統(tǒng)

    目錄 文件系統(tǒng) 背景知識(shí) 磁盤結(jié)構(gòu) 磁盤的存儲(chǔ)結(jié)構(gòu) 磁盤抽象(邏輯,虛擬)結(jié)構(gòu) BootBlock: Super block Data blocks inode Table BlcokBitmap inode Bitmap Group Descriptor Table? 文件名和inode編號(hào) 硬鏈接和軟鏈接 軟鏈接 硬鏈接 取消軟硬鏈接unlink stderr 我們講解文件系統(tǒng)之前還需要說(shuō)一些背景知識(shí),

    2024年02月15日
    瀏覽(21)
  • Linux 深入理解Linux文件系統(tǒng)與日志分析

    Linux 深入理解Linux文件系統(tǒng)與日志分析

    文件數(shù)據(jù) 包含 元信息(即不包含文件名的文件屬性) ? ?和? ? 實(shí)際數(shù)據(jù) 文件元信息存儲(chǔ)在 inode(索引節(jié)點(diǎn))里, 文件實(shí)際數(shù)據(jù)存儲(chǔ)在 block(塊)里; 文件名存儲(chǔ)在目錄塊里 stat? 文件名 ? stat? 文件名? ? ? ls -i 文件名 ? df -i Linux系統(tǒng)不使用 文件名 識(shí)別文件,而 使用 inode號(hào) 來(lái)識(shí)

    2024年04月25日
    瀏覽(28)
  • 【linux深入剖析】深入理解基礎(chǔ)外設(shè)--磁盤以及理解文件系統(tǒng)

    【linux深入剖析】深入理解基礎(chǔ)外設(shè)--磁盤以及理解文件系統(tǒng)

    ??你好,我是 RO-BERRY ?? 致力于C、C++、數(shù)據(jù)結(jié)構(gòu)、TCP/IP、數(shù)據(jù)庫(kù)等等一系列知識(shí) ??感謝你的陪伴與支持 ,故事既有了開(kāi)頭,就要畫(huà)上一個(gè)完美的句號(hào),讓我們一起加油 我們所有的文件都是與進(jìn)程相關(guān)的文件–進(jìn)程打開(kāi)的文件 系統(tǒng)中是不是所有的文件都被打開(kāi)了呢?如果沒(méi)

    2024年04月11日
    瀏覽(24)
  • 【Linux】封裝一下簡(jiǎn)單庫(kù) && 理解文件系統(tǒng)

    【Linux】封裝一下簡(jiǎn)單庫(kù) && 理解文件系統(tǒng)

    提示:文章寫(xiě)完后,目錄可以自動(dòng)生成,如何生成可參考右邊的幫助文檔 目錄 前言 一、封裝一下簡(jiǎn)單庫(kù) 二、理解一下stdin(0)、stdout(1)、stderr(3) 2.1、為什么要有0、1、2呢? 2.2、特點(diǎn) 2.3、如果我想讓2也和1重定向到一個(gè)文件中? 三、理解文件系統(tǒng) 3.1、看看物理磁盤 3.2、了解

    2024年04月22日
    瀏覽(15)
  • Linux Centos系統(tǒng) 磁盤分區(qū)和文件系統(tǒng)管理 (深入理解)

    Linux Centos系統(tǒng) 磁盤分區(qū)和文件系統(tǒng)管理 (深入理解)

    作者主頁(yè): 點(diǎn)擊! Linux專欄:點(diǎn)擊! 磁盤 在Linux系統(tǒng)中,磁盤是一種用于存儲(chǔ)數(shù)據(jù)的物理設(shè)備,可以是傳統(tǒng)的硬盤驅(qū)動(dòng)器(HDD)或固態(tài)硬盤(SSD)。Linux將磁盤設(shè)備視為塊設(shè)備,它們通常以文件形式表示在 /dev 目錄下。 文件系統(tǒng) 在計(jì)算機(jī)系統(tǒng)中, 文件系統(tǒng) 定義了如何存儲(chǔ)

    2024年03月15日
    瀏覽(23)
  • 【Linux】深入理解系統(tǒng)文件操作(1w字超詳解)

    【Linux】深入理解系統(tǒng)文件操作(1w字超詳解)

    ?是不是只有CC++有文件操作呢???Python、Java、PHP、go也有,他們的文件操作的方法是不一樣的啊 1.1對(duì)于文件操作的思考: 我們之前就說(shuō)過(guò)了: 文件=內(nèi)容+屬性 針對(duì)文件的操作就變成了對(duì)內(nèi)容的操作和對(duì)屬性的操作 ?當(dāng)文件沒(méi)有被操作的時(shí)候,文件一般會(huì)在什么位置???

    2024年02月07日
    瀏覽(26)
  • Linux 系統(tǒng)調(diào)用IO口,利用光標(biāo)偏移實(shí)現(xiàn)文件復(fù)制

    Linux 系統(tǒng)調(diào)用IO口,利用光標(biāo)偏移實(shí)現(xiàn)文件復(fù)制

    用系統(tǒng)調(diào)用IO函數(shù)實(shí)現(xiàn)從一個(gè)文件讀取最后2KB數(shù)據(jù)并復(fù)制到另一個(gè)文件中,源文件以只讀方式打開(kāi),目標(biāo)文件以只寫(xiě)的方式打開(kāi),若目標(biāo)文件不存在,可以創(chuàng)建并設(shè)置初始值為0664,寫(xiě)出相應(yīng)代碼,要對(duì)出錯(cuò)情況有一定的處理,并能夠讓用戶自行輸入要復(fù)制的文件名。 IO口即指

    2024年02月08日
    瀏覽(19)
  • [Linux]基礎(chǔ)IO詳解(系統(tǒng)文件I/O接口、文件描述符、理解重定向)

    [Linux]基礎(chǔ)IO詳解(系統(tǒng)文件I/O接口、文件描述符、理解重定向)

    ? ? ? ? hello,大家好,這里是bang___bang_ ,今天和大家談?wù)凩inux中的基礎(chǔ)IO,包含內(nèi)容有對(duì)應(yīng)的系統(tǒng)文件I/O接口,文件描述符,理解重定向。 ?? 目錄 1??初識(shí)文件 2?? 系統(tǒng)文件I/O接口 ??open ??write ??read ??close 3??文件描述符 ??012 ??內(nèi)核中文件描述符的探究 ??分配

    2024年02月12日
    瀏覽(20)
  • 【Linux從入門到精通】文件I/O操作(C語(yǔ)言vs系統(tǒng)調(diào)用)

    【Linux從入門到精通】文件I/O操作(C語(yǔ)言vs系統(tǒng)調(diào)用)

    文章目錄 一、C語(yǔ)言的文件IO相關(guān)函數(shù)操作 1、1 fopen與fclose 1、2 fwrite 1、3 fprintf與fscanf 1、4?fgets與fputs 二、系統(tǒng)調(diào)用相關(guān)接口 2、1 open與close 2、2 write和read 三、簡(jiǎn)易模擬實(shí)現(xiàn)cat指令 四、總結(jié) ???♂??作者:@Ggggggtm????♂? ???專欄:Linux從入門到精通? ?? ???標(biāo)題:文

    2024年02月13日
    瀏覽(18)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包