1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Linux 基礎(chǔ) - IO 全面介紹

        共 11757字,需瀏覽 24分鐘

         ·

        2022-06-27 19:17

        在公眾號(hào)后臺(tái)回復(fù):JGNB,可獲取杰哥原創(chuàng)的 PDF 手冊(cè)。

        Linux - 基礎(chǔ) IO

        • Linux - 基礎(chǔ) IO

        • 文件 IO 相關(guān)操作

        • stdin & stdout & stderr

        • 系統(tǒng)文件 I/O

        文件的宏觀理解:

        狹義理解:

        1.文件在磁盤里
        2.磁盤是永久性存儲(chǔ)介質(zhì),因此文件在磁盤上的存儲(chǔ)是永久性的
        3.磁盤是外設(shè)(即是輸出設(shè)備也是輸入設(shè)備)
        4.磁盤上的文件 本質(zhì)是對(duì)文件的所有操作,都是對(duì)外設(shè)的輸入和輸出 簡稱 IO

        廣義理解:

        1.Linux 下一切皆文件(鍵盤、顯示器、網(wǎng)卡、磁盤…… 這些都是抽象化的過程)

        文件操作的歸類認(rèn)知:

        1.對(duì)于 0KB 的空文件是占用磁盤空間的
        2.文件是文件屬性(元數(shù)據(jù))和文件內(nèi)容的集合(文件 = 屬性(元數(shù)據(jù))+ 內(nèi)容)
        3.所有的文件操作本質(zhì)是文件內(nèi)容操作和文件屬性操作

        系統(tǒng)角度:

        1.對(duì)文件的操作本質(zhì)是進(jìn)程對(duì)文件的操作
        2.磁盤的管理者是操作系統(tǒng)
        3.文件的讀寫本質(zhì)不是通過 C 語言 / C++ 的庫函數(shù)來操作的(這些庫函數(shù)只是為用戶提供方便),而是通過文件相關(guān)的系統(tǒng)調(diào)用接口來實(shí)現(xiàn)的

        文件 IO 相關(guān)操作

        int fputs(const char *s, FILE *stream);

        fputs 函數(shù)是將 s 所指向的數(shù)據(jù)往 stream 中所指向的文件中寫

        char * fgets char * str, int num, FILE * stream )

        注:

        • 從流中讀取字符并將它們作為 C 字符串存儲(chǔ)到 str 中,直到讀取 (num-1) 個(gè)字符或到達(dá)換行符或文件結(jié)尾,以先發(fā)生者為準(zhǔn)。

        • 換行符使 fgets 停止讀取,但它被函數(shù)視為有效字符并包含在復(fù)制到 str 的字符串中。

        • 在復(fù)制到 str 的字符之后會(huì)自動(dòng)附加一個(gè)終止空字符。

        • fgets 與 get 完全不同:fgets 不僅接受流參數(shù),還允許指定 str 的最大大小并在字符串中包含任何結(jié)束的換行符。

        fwrite 的使用方法

        • 當(dāng)前路徑指的是每個(gè)進(jìn)程,都有一個(gè)內(nèi)置的屬性 cwd

        • fwrite 函數(shù)如果 size_t count 傳入的數(shù)正好將字符串內(nèi)容全部傳入到指定文本中則返回 count,否則返回與 count 不同的數(shù)

        • fwrite 函數(shù)傳入內(nèi)容的大小正好是 size_t size, 和 size_t count 的乘積

        stdin & stdout & stderr

        • 任何 C 程序,都默認(rèn)打開三個(gè)文件分別叫做標(biāo)準(zhǔn)輸入(stdin)、標(biāo)準(zhǔn)輸出(stdout)、標(biāo)準(zhǔn)錯(cuò)誤(stderr)

        • 標(biāo)準(zhǔn)輸入(stdin)——鍵盤文件——讀方法(read)

        • 標(biāo)準(zhǔn)輸出(stdout)、標(biāo)準(zhǔn)錯(cuò)誤(stderr)——顯示器文件——寫方法(write)

        • Linux 下一切皆文件

        • 所有的外設(shè)硬件,本質(zhì)是對(duì)應(yīng)的核心操作無外乎是 read 和 write(不同的硬件對(duì)應(yīng)的讀寫方式是不一樣的)

        注:

        • 可以通過 C 接口,直接對(duì) stdin、stdout、stderr 進(jìn)行讀寫

        • C 默認(rèn)會(huì)打開三個(gè)輸入輸出流,分別是 stdin, stdout, stderr, 這樣做便于語言進(jìn)行上手使用,都有輸入輸出的需求

        • 幾乎所有的編程語言都會(huì)默認(rèn)會(huì)打開三個(gè)輸入輸出流 stdin, stdout, stderr,

        • 任何一種編程語言的文件操作相關(guān)的函數(shù)(庫函數(shù))底層都會(huì)調(diào)用系統(tǒng)調(diào)用接口(open、close、write、- read,這些在 Linux 系統(tǒng)下有,但這些接口不具備可移植性)

        • 語言上相關(guān)文件操作的庫函數(shù)兼容自身語法特征,系統(tǒng)調(diào)用使用成本較高,而且不具備可移植性

        系統(tǒng)文件 I/O

        open

        #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: 要打開或創(chuàng)建的目標(biāo)文件
        flags: 打開文件時(shí),可以傳入多個(gè)參數(shù)選項(xiàng),用下面的一個(gè)或者多個(gè)常量進(jìn)行“或”運(yùn)算,構(gòu)成flags。
        參數(shù):
           O_RDONLY: 只讀打開
           O_WRONLY: 只寫打開
           O_RDWR : 讀,寫打開
             這三個(gè)常量,必須指定一個(gè)且只能指定一個(gè)
           O_CREAT : 若文件不存在,則創(chuàng)建它。需要使用mode選項(xiàng),來指明新文件的訪問權(quán)限
           O_APPEND: 追加寫
         返回值:
             成功:新打開的文件描述符
            失敗:-1

        注:

        • open 函數(shù)具體使用哪個(gè),和具體應(yīng)用場景相關(guān),如目標(biāo)文件不存在,需要 open 創(chuàng)建,則第三個(gè)參數(shù)表示創(chuàng)建文件的默認(rèn)權(quán)限, 否則,使用兩個(gè)參數(shù)的 open。

        • O_RDONLY、O_WRONLY、O_RDWR…… 這些都是系統(tǒng)定義的宏,這些參數(shù)只占一個(gè) int 整形中的一個(gè)比特位

        注:write read close lseek…… 與 C 語言文件相關(guān)接口用法類似

        文件描述符 fd

        注:

        • 用戶層看到的 fd 本質(zhì)是系統(tǒng)中維護(hù)進(jìn)程和文件對(duì)應(yīng)關(guān)系的數(shù)組的下標(biāo)

        • 所謂的默認(rèn)打開文件,標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出,標(biāo)準(zhǔn)錯(cuò)誤,其實(shí)是由底層系統(tǒng)支持的,默認(rèn)一個(gè)進(jìn)程在運(yùn)行的時(shí)候,就打開了 0,1,2

        • 對(duì)于進(jìn)程來講,對(duì)所有的文件進(jìn)行操作,統(tǒng)一使用一套接口(一組函數(shù)指針),因此在 OS 看來一切皆文件

        文件描述符就是從 0 開始的小整數(shù)。當(dāng)打開文件時(shí),操作系統(tǒng)在內(nèi)存中要?jiǎng)?chuàng)建相應(yīng)的數(shù)據(jù)結(jié)構(gòu)來描述目標(biāo)文件。于是就有了 file 結(jié)構(gòu)體。表示一個(gè)已經(jīng)打開的文件對(duì)象。而進(jìn)程執(zhí)行 open 系統(tǒng)調(diào)用,所以必須讓進(jìn)程和文件關(guān)聯(lián)起來。每個(gè)進(jìn)程都有一個(gè)指針 files_struct*, 指向一張表 files_struct, 該表最重要的部分就是包涵一個(gè)指針數(shù)組,每個(gè)元素都是一個(gè)指向打開文件的指針!所以,本質(zhì)上,文件描述符就是該數(shù)組的下標(biāo)。只要拿著文件描述符,就可以找到對(duì)應(yīng)的文件

        補(bǔ)充:

        • 標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤在對(duì)應(yīng)的文件描述符為 0,1,2,對(duì)應(yīng) C 語言層上的是 stdin、stdout、stderr

        • 所有文件,如果要被使用時(shí),首先必須被打開

        • 一個(gè)進(jìn)程可以打開多個(gè)文件,系統(tǒng)中被打開的文件一定有多個(gè),多個(gè)被打開的文件,一定要被操作系統(tǒng)管理起來的(先描述(struct file(包含了目標(biāo)文件的基本操作和部分屬性)),再組織(雙鏈表))

        • 打開文件的過程:先在 fd_array 數(shù)組中找一個(gè)最小的沒有被使用的數(shù)組下標(biāo)位置,然后把新 open 出的文件的結(jié)構(gòu)體地址填入到數(shù)組中去,對(duì)應(yīng)該地址的下標(biāo)返回給對(duì)應(yīng)的進(jìn)程

        • fd:本質(zhì)是進(jìn)程和文件之間對(duì)應(yīng)關(guān)系的數(shù)組的下標(biāo),有了 fd 就可以找到打開文件的所有細(xì)節(jié)

        文件描述符的分配規(guī)則

        總結(jié):

        • 文件描述符的分配規(guī)則:在 files_struct 數(shù)組當(dāng)中,找到當(dāng)前沒有被使用的最小的一個(gè)下標(biāo),作為新的文件描述符

        • Linux 進(jìn)程默認(rèn)情況下會(huì)有 3 個(gè)缺省打開的文件描述符,分別是標(biāo)準(zhǔn)輸入 0, 標(biāo)準(zhǔn)輸出 1, 標(biāo)準(zhǔn)錯(cuò)誤 2

        重定向

        補(bǔ)充:程序替換的時(shí)候不會(huì)影響重定向?qū)?yīng)的數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)(程序替換影響的是進(jìn)程虛擬地址空間部分,而重定向影響的是 files_struct 部分)

        使用 dup2 系統(tǒng)調(diào)用

        #include <unistd.h>
        int dup2(int oldfd, int newfd);

        注:

        newfd 使 oldfd 的一份拷貝,不是拷貝 fd 而是拷貝 fd 對(duì)應(yīng)的 fd_array 數(shù)組中的內(nèi)容

        FILE

        因?yàn)?IO 相關(guān)函數(shù)與系統(tǒng)調(diào)用接口對(duì)應(yīng),并且?guī)旌瘮?shù)封裝系統(tǒng)調(diào)用,所以本質(zhì)上,訪問文件都是通過 fd 訪問的。因此 C 庫當(dāng)中的 FILE 結(jié)構(gòu)體內(nèi)部,必定封裝了 fd

        typedef struct _IO_FILE FILE; 在/usr/include/stdio.h
        在/usr/include/libio.h
        struct _IO_FILE {
         int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
        #define _IO_file_flags _flags
         //緩沖區(qū)相關(guān)
         /* 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
        };

        總結(jié):

        • FILE 結(jié)構(gòu)體中包含了 int fileno 的成員(也就是系統(tǒng)上的 fd 文件描述符)

        • fopen、fwrite、fread、fclose 等 f 系列的庫函數(shù)都是由底層 open、write 、read、close 實(shí)現(xiàn)的,通過 open 的返回值傳給 fileno,從而對(duì)系統(tǒng)調(diào)用函數(shù)進(jìn)行封裝

        • struct FILE 內(nèi)部包含:底層對(duì)應(yīng)的文件描述符下標(biāo)、應(yīng)用層 C 語言提供的緩沖區(qū)數(shù)據(jù)

        • 所謂的默認(rèn)打開文件,標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤其實(shí)是由底層系統(tǒng)支持的,默認(rèn)一個(gè)進(jìn)程在運(yùn)行的時(shí)候,就打開了 0,1,2

        一般 C 庫函數(shù)寫入文件時(shí)是全緩沖的,而寫入顯示器是行緩沖。printf fprintf 等庫函數(shù)會(huì)自帶緩沖區(qū),當(dāng)發(fā)生重定向到普通文件時(shí),數(shù)據(jù)的緩沖方式由行緩沖變成了全緩沖。而我們放在緩沖區(qū)中的數(shù)據(jù),就不會(huì)被立即刷新,甚至 fork 之后但是進(jìn)程退出之后,會(huì)統(tǒng)一刷新,寫入文件當(dāng)中。但是 fork 的時(shí)候,父子數(shù)據(jù)會(huì)發(fā)生寫時(shí)拷貝,所以當(dāng)你父進(jìn)程準(zhǔn)備刷新的時(shí)候,子進(jìn)程也就有了同樣的一份數(shù)據(jù),隨即產(chǎn)生兩份數(shù)據(jù)。write 沒有變化,說明沒有所謂的緩沖
        printf fputs 等 庫函數(shù)會(huì)自帶緩沖區(qū),而 write 系統(tǒng)調(diào)用沒有帶緩沖區(qū)。另外,我們這里所說的緩沖區(qū),都是用戶級(jí)緩沖區(qū)。其實(shí)為了提升整機(jī)性能,OS 也會(huì)提供相關(guān)內(nèi)核級(jí)緩沖區(qū)。printf fprintf 是庫函數(shù), write 是系統(tǒng)調(diào)用,庫函數(shù)在系統(tǒng)調(diào)用的 “上層”, 是對(duì)系統(tǒng)調(diào)用的 “封裝”,但是 write 有內(nèi)核級(jí)緩沖區(qū),而 printf fwrite fputs 等緩沖區(qū)是用戶級(jí)緩沖區(qū),由 C 標(biāo)準(zhǔn)庫提供

        注:系統(tǒng)調(diào)用函數(shù)與庫函數(shù)盡量不要混在一起使用,可能會(huì)與統(tǒng)一使用的函數(shù)的運(yùn)行結(jié)果有所差異

        文件系統(tǒng)

        文件:打開的文件、普通未打開的文件
        打開的文件:屬性與操作方法的表現(xiàn)就是 struct file{} 屬于內(nèi)存級(jí)文件
        普通未打開的文件:磁盤上面未被加載到內(nèi)存的
        文件系統(tǒng)功能:將上述的這些文件管理起來

        磁盤

        磁盤是計(jì)算機(jī)主要的存儲(chǔ)介質(zhì),可以存儲(chǔ)大量的二進(jìn)制數(shù)據(jù),并且斷電后也能保持?jǐn)?shù)據(jù)不丟失。早期計(jì)算機(jī)使用的磁盤是軟磁盤(Floppy Disk,簡稱軟盤),如今常用的磁盤是硬磁盤(Hard disk,簡稱硬盤)。

        補(bǔ)充:

        • 內(nèi)存在操作系統(tǒng)的角度使用的時(shí)候,基本單位是 4KB,但在使用角度是 1 字節(jié)

        • 磁盤存儲(chǔ)的基本單位是扇區(qū)(512 字節(jié))(磁盤讀取的最小單元)

        • 內(nèi)存與磁盤間 IO 時(shí),基本單位是 4KB,是通過文件系統(tǒng)來完成的

        磁盤的劃分

        我們可以將磁盤想象成磁帶(線性結(jié)構(gòu)),將磁盤看成一個(gè)線性空間(數(shù)組),類型為扇區(qū)的數(shù)組、數(shù)組個(gè)數(shù)為 10 億多

        這樣劃分就不用讓 OS 讀取數(shù)據(jù)時(shí)在哪個(gè)盤面、哪個(gè)磁道、哪個(gè)扇區(qū)找了,OS 與磁盤映射關(guān)系可以通過磁盤驅(qū)動(dòng)來完成,這樣也就做到強(qiáng)解耦性。無論換機(jī)械硬盤還是固態(tài)硬盤,OS 都不用改變讀取磁盤數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu),只需改變磁盤的驅(qū)動(dòng)程序即可

        注:操作系統(tǒng)讀取磁盤數(shù)據(jù)時(shí)的下標(biāo)——LBA

        • 磁盤經(jīng)過在 OS 中的虛擬化成數(shù)組,但是所占空間太大,因此需要進(jìn)行分區(qū)化管理,并對(duì)該區(qū)域進(jìn)行格式化(寫入文件系統(tǒng)(數(shù)據(jù)和方法))。eg:Windows 中的 C 盤、D 盤……

        • 每個(gè)分區(qū)再進(jìn)行分組——塊組

        • Linux 系統(tǒng)下支持多種文件系統(tǒng):Ext2、Ext3、fs、usb-fs、sysfs、proc

        inode

        Linux ext2 文件系統(tǒng),上圖為磁盤文件系統(tǒng)圖(內(nèi)核內(nèi)存映像肯定有所不同),磁盤是典型的塊設(shè)備,硬盤分區(qū)被劃分為一個(gè)個(gè)的 block。一個(gè) block 的大小是由格式化的時(shí)候確定的,并且不可以更改。例如 mke2fs 的 - b 選項(xiàng)可以設(shè) 定 block 大小為 1024、2048 或 4096 字節(jié)。而啟動(dòng)塊(Boot Block)的大小是確定的,

        • Block Group:ext2 文件系統(tǒng)會(huì)根據(jù)分區(qū)的大小劃分為數(shù)個(gè) Block Group。而每個(gè) Block Group 都有著相同的結(jié)構(gòu)組成。

        • 超級(jí)塊(Super Block):存放文件系統(tǒng)本身的結(jié)構(gòu)信息。記錄的信息主要有:bolck 和 inode 的總量,未使用的 block 和 inode 的數(shù)量,一個(gè) block 和 inode 的大小,最近一次掛載的時(shí)間,最近一次寫入數(shù)據(jù)的時(shí)間,最近一次檢驗(yàn)磁盤的時(shí)間等其他文件系統(tǒng)的相關(guān)信息。Super Block 的信息被破壞,可以說整個(gè)文件系統(tǒng)結(jié)構(gòu)就被破壞了

        • GDT,Group Descriptor Table:塊組描述符,描述塊組屬性信息

        • 塊位圖(Block Bitmap):Block Bitmap 中記錄著 Data Block 中哪個(gè)數(shù)據(jù)塊已經(jīng)被占用,哪個(gè)數(shù)據(jù)塊沒有被占用

        • inode 位圖(inode Bitmap):每個(gè) bit 表示一個(gè) inode 是否空閑可用。

        • i 節(jié)點(diǎn)表: 存放文件屬性 如 文件大小,所有者,最近修改時(shí)間等

        • 數(shù)據(jù)區(qū):存放文件內(nèi)容

        注:

        • Block Group 每個(gè)塊組中都有,但是 Super Block 并不是每個(gè)塊組中都有

        • 每一個(gè)文件都對(duì)應(yīng)一個(gè) inode 節(jié)點(diǎn)

        總結(jié):

        • 基本上,一個(gè)文件一個(gè) inode(包括文件)

        • inode 是一個(gè)文件的所有的屬性集合(不包含文件名)(空文件也是占據(jù)空間的,所有的屬性也是數(shù)據(jù)也要占據(jù)空間)

        • 真正表示文件的不是文件名,而是文件的 inode 編號(hào)

        • inode 是可以和特定的數(shù)據(jù)塊產(chǎn)生關(guān)聯(lián)的

        • 程序員是通過路徑定位的(目錄)來定位一個(gè)文件,而操作系統(tǒng)是通過目錄的 Data blocks 來確定文件名和 inode 的映射關(guān)系

        • 目錄是文件,有獨(dú)立的 inode 和數(shù)據(jù)塊

        創(chuàng)建一個(gè)新文件主要有一下 4 個(gè)操作:

        • 存儲(chǔ)屬性 ——內(nèi)核先找到一個(gè)空閑的 i 節(jié)點(diǎn)。內(nèi)核把文件信息記錄到其中。

        • 存儲(chǔ)數(shù)據(jù) ——該文件需要存儲(chǔ)在三個(gè)磁盤塊,內(nèi)核找到了三個(gè)空閑塊。將內(nèi)核緩沖區(qū)數(shù)據(jù)緩沖到磁盤的數(shù)據(jù)區(qū)中

        • 記錄分配情況——文件內(nèi)容按順序存放(數(shù)據(jù)塊)。內(nèi)核在 inode 上的磁盤分布區(qū)記錄了上述塊列表。

        • 添加文件名到目錄——內(nèi)核將入口添加到目錄文件。文件名和 inode 之間的對(duì)應(yīng)關(guān)系將文件名和文件的內(nèi)容及屬性連接起來。

        補(bǔ)充:

        • inode 描述了文件大小和指向數(shù)據(jù)塊的指針

        • 通過 inode 可獲得文件占用的塊數(shù)

        • 通過 inode 可實(shí)現(xiàn)文件的邏輯結(jié)構(gòu)和物理結(jié)構(gòu)的轉(zhuǎn)換

        軟硬連接

        硬鏈接:

        硬鏈接的應(yīng)用場景:方便進(jìn)行相對(duì)路徑的路徑的設(shè)置

        因此,可以看出.、… 的底層實(shí)現(xiàn)是通過硬鏈接的方式來實(shí)現(xiàn)的

        注:

        • 真正找到磁盤上文件的并不是文件名,而是 inode。其實(shí)在 linux 中可以讓多個(gè)文件名對(duì)應(yīng)于同一個(gè) inode

        • 在刪除文件時(shí)干了兩件事情:1. 在目錄中將對(duì)應(yīng)的記錄刪除,2. 將硬連接數(shù) - 1,如果為 0,則將對(duì)應(yīng)的磁盤釋放。

        軟鏈接:

        注:硬鏈接是通過 inode 引用另外一個(gè)文件,軟鏈接是通過名字引用另外一個(gè)文件

        總結(jié):軟硬鏈接的區(qū)別:本質(zhì)是是否是獨(dú)立文件,有無獨(dú)立 inode;用途:軟鏈接可以指向特定的文件方便進(jìn)行快速索引,硬鏈接是能進(jìn)行相對(duì)路徑設(shè)置

        補(bǔ)充:

        • 軟鏈接文件是一個(gè)獨(dú)立的文件有自己的 inode 節(jié)點(diǎn),通過數(shù)據(jù)中保存的源文件路徑訪問源文件

        • 硬鏈接是文件的一個(gè)目錄項(xiàng),與源文件共用同一個(gè) inode 節(jié)點(diǎn),直接通過自己的 inode 節(jié)點(diǎn)訪問源文件

        • 不同分區(qū)有可能有不同文件系統(tǒng),因此硬鏈接不能跨分區(qū)建立;軟連接可以跨文件系統(tǒng)進(jìn)行連接,硬鏈接不可以

        • 當(dāng)刪除源文件時(shí),軟鏈接文件失效

        • ln 生成符號(hào)鏈接文件指的是 ln -s 生成軟鏈接文件

        文件的 ACM

        總結(jié):

        • Access 最后訪問時(shí)間

        • Modify 文件內(nèi)容最后修改時(shí)間

        • Change 屬性最后修改時(shí)間

        文件的 ACM 的應(yīng)用場景:

        動(dòng)態(tài)庫和靜態(tài)庫

        靜態(tài)庫與動(dòng)態(tài)庫

        • 使用頂尖的工程師寫的代碼是為了開發(fā)效率和魯棒性(健壯性)

        • 使用頂尖的工程師寫的功能一般通過庫、開源代碼、基本的網(wǎng)絡(luò)功能調(diào)用(各種網(wǎng)絡(luò)接口、語音識(shí)別)

        • 庫分為動(dòng)態(tài)庫和靜態(tài)庫

        • 庫的命名:取消前綴 lib,去掉. 之后的內(nèi)容,剩下的就是庫的名字

        • 生成可執(zhí)行程序的方式有兩種:動(dòng)態(tài)鏈接、靜態(tài)鏈接

        注:

        • ldd 可以列出一個(gè)程序所需要得動(dòng)態(tài)鏈接庫;file 命令用于辨識(shí)文件類型

        • Linux 中,默認(rèn)情況下形成的可執(zhí)行程序是動(dòng)態(tài)鏈接的

        • 將庫中的我的可執(zhí)行程序中使用的二進(jìn)制代碼,拷貝進(jìn)我的可執(zhí)行程序中——靜態(tài)鏈接

        • 一般為了更好的支持開發(fā),第三方庫或者語言庫都必須提供兩個(gè)庫,一個(gè)叫做靜態(tài)庫,一個(gè)叫做動(dòng)態(tài)庫,方便程序員根據(jù)需要進(jìn)行可執(zhí)行程序的生成

        • 動(dòng)態(tài)鏈接的特點(diǎn):體積小、節(jié)省資源(磁盤、內(nèi)存),依賴庫,一旦丟失可執(zhí)行程序不可執(zhí)行

        • 靜態(tài)鏈接的特點(diǎn):體積大、浪費(fèi)資源(磁盤、內(nèi)存),不依賴庫,庫丟失,可執(zhí)行程序不受影響

        總結(jié):

        • 靜態(tài)庫(.a):程序在編譯鏈接的時(shí)候把庫的代碼鏈接到可執(zhí)行文件中。程序運(yùn)行的時(shí)候?qū)⒉辉傩枰o態(tài)庫

        • 動(dòng)態(tài)庫(.so):程序在運(yùn)行的時(shí)候才去鏈接動(dòng)態(tài)庫的代碼,多個(gè)程序共享使用庫的代碼。

        • 一個(gè)與動(dòng)態(tài)庫鏈接的可執(zhí)行文件僅僅包含它用到的函數(shù)入口地址的一個(gè)表,而不是外部函數(shù)所在目標(biāo)文件的整個(gè)機(jī)器碼

        • 在可執(zhí)行文件開始運(yùn)行以前,外部函數(shù)的機(jī)器碼由操作系統(tǒng)從磁盤上的該動(dòng)態(tài)庫中復(fù)制到內(nèi)存中,這個(gè)過程稱為動(dòng)態(tài)鏈接(dynamic linking)

        • 動(dòng)態(tài)庫可以在多個(gè)程序間共享,所以動(dòng)態(tài)鏈接使得可執(zhí)行文件更小,節(jié)省了磁盤空間。操作系統(tǒng)采用虛擬內(nèi)存機(jī)制允許物理內(nèi)存中的一份動(dòng)態(tài)庫被要用到該庫的所有進(jìn)程共用,節(jié)省了內(nèi)存和磁盤空間

        生成靜態(tài)庫

        [root@localhost linux]# ls
        add.c add.h main.c sub.c sub.h
        [root@localhost linux]# gcc -c add.c -o add.o
        [root@localhost linux]# gcc -c sub.c -o sub.o
        生成靜態(tài)庫
        [root@localhost linux]# ar -rc libmymath.a add.o sub.o 
        ar是gnu歸檔工具,rc表示(replace and create)
        查看靜態(tài)庫中的目錄列表
        [root@localhost linux]# ar -tv libmymath.a 
        rw-r--r-- 0/0 1240 Sep 15 16:53 2017 add.o
        rw-r--r-- 0/0 1240 Sep 15 16:53 2017 sub.o
        t:列出靜態(tài)庫中的文件
        v:verbose 詳細(xì)信息
        [root@localhost linux]# gcc main.c -I -L. -lmymath
        -L 指定庫路徑
        -I 指定頭文件路徑
        -l 指定庫名
        測試目標(biāo)文件生成后,靜態(tài)庫刪掉,程序照樣可以運(yùn)行

        注:

        • -I:告訴 gcc 除了默認(rèn)路徑(/usr/include)以及當(dāng)前路徑之外,在指定路徑下也找一下頭文件

        • -L:告訴 gcc 除了默認(rèn)路徑 (/lib/ 、/lib64 、/lib64/libc*) 以及當(dāng)前路徑之外,在指定路徑下也找一下庫文件

        • -l 庫名稱:具體鏈接哪個(gè)庫

        C 語言編譯時(shí)直接編譯不用任何選項(xiàng):

        • 1.庫文件和頭文件在默認(rèn)路徑下 gcc 能找到

        • 2.gcc 編譯 C 語言代碼默認(rèn)應(yīng)該鏈接 libc

        當(dāng)自己的可執(zhí)行程序編譯時(shí)不想用這些選項(xiàng):將頭文件和庫文件分別拷貝到默認(rèn)路徑下——庫的安裝(第三方庫)(使用時(shí)必須帶上 - l 庫名稱) 當(dāng)只有靜態(tài)庫時(shí),沒有動(dòng)態(tài)庫,用 gcc 編譯(不加 - static)會(huì)直接用靜態(tài)鏈接生成可執(zhí)行程序

        補(bǔ)充:

        • 庫搜索路徑:

        • 從左到右搜索 - L 指定的目錄。

        • 由環(huán)境變量指定的目錄 (LIBRARY_PATH)

        • 由系統(tǒng)指定的目錄
          /usr/lib
          /usr/local/lib

        生成動(dòng)態(tài)庫

        • shared: 表示生成共享庫格式

        • fPIC:產(chǎn)生位置無關(guān)碼 (position independent code)

        • 庫名規(guī)則:libxxx.so

        補(bǔ)充:

        • 動(dòng)態(tài)庫被加載在內(nèi)存中,可以供多個(gè)使用庫的程序共享映射到自己的虛擬地址空間使用,因此可以減少頁面交換以及降低內(nèi)存中代碼冗余,并且因?yàn)榕c源程序模塊分離,因此開發(fā)模式比較好

        • 加載動(dòng)態(tài)庫的程序運(yùn)行速度相對(duì)較慢,因?yàn)閯?dòng)態(tài)庫運(yùn)行時(shí)加載,映射到虛擬地址空間后需要重新根據(jù)映射起始地址計(jì)算函數(shù) / 變量地址

        • 靜態(tài)庫會(huì)被添加為程序的一部分進(jìn)行使用

        • 動(dòng)態(tài)庫可用節(jié)省內(nèi)存和磁盤空間

        • 靜態(tài)庫重新編譯,需要將應(yīng)用程序重新編譯

        運(yùn)行動(dòng)態(tài)庫

        1.拷貝. so 文件到系統(tǒng)共享庫路徑下, 一般指 / usr/lib

        2.更改 LD_LIBRARY_PATH(當(dāng)系統(tǒng)重啟時(shí)使用之前添加的是無效的,應(yīng)重新添加)

        export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:路徑

        3.ldconfig 配置 / etc/ld.so.conf.d/,ldconfig 更新

        作者:The August
        https://blog.csdn.net/AI_ELF/article/details/122547439

        推薦閱讀

        find 命令的 7 種用法

        8 個(gè)常用的 Wireshark 使用技巧

        100+ 道 Linux 面試題(附答案及PDF)

        Linux 實(shí)用運(yùn)維腳本分享

        43 個(gè) Bash 編程易錯(cuò)總結(jié)大全!

        瀏覽 54
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            操操操操av | jzzijzzij亚洲成熟少妇在线播放 | 小丽的性荡生活 | 国产精品视频在线观看 | a视频观看 | ass漂亮女人下部picasa | 国产激情视频在线观看 | 久热只有精品 | 手机在线毛片 | 豆花视频18成人入口 |