unix環境高級編程(上)-文件篇

目錄

前言

unix基礎知識

unix標準化和實現

unix提供的文件IO

文件和目錄

標準IO

系統數據文件

前言

筆者將《unix環境高級編程》主要內容總結爲三篇:文件篇進程篇高級io和進程間通訊三大板塊。本文是unix環境高級編程系列文章第一篇:文件篇。該篇主要包括:node

unix基礎知識

介紹了unix的體系結構,以及unix中的文件和目錄,輸入輸出,程序和進程,信號等基本概念shell

unix標準與實現

標準包括C語言的標準和操做系統標準,實現包括BSD,FreeBSD,Linux,Solari,Mac os等數據庫

unix內核提供的文件io函數

包括文件描述符,對文件的打開,關閉,定位,讀,寫,改變文件屬性操做。內核IO調用基於文件描述符。還介紹了文件的底層數據結構,瞭解數據結構以後就能理解文件是如何支持共享的編程

文件和目錄

主要介紹文件的屬性和屬性對應的數據結構,以及各個字段控制的問訪問權限,文件類型等。unix中一切皆文件,這些文件包括:普通文件,目錄文件,塊特殊文件,字符特殊文件,FIFO,套接字和符號連接。最後結束UFS文件系統。數組

標準IO函數

標準io解決了內核io的不少細節問題,包括緩衝區分配。全部操做基於流和File對象緩存

系統數據文件

最後介紹系統提供的一些數據文件,包括口令文件,陰影文件,朱文傑,登陸帳號文件,服務數據文件,協議數據文件,網絡數據文件等bash

一. unix基礎知識

1. unix體系結構

  • 操做系統是一種特殊的軟件,它控制計算機硬件資源,提供程序運行環境
  • 此軟件稱爲內核,它相對較小,位於環境的中心
  • 內核的接口被稱爲系統調用
  • 公共函數庫構建在系統調用接口上
  • 系統調用通常比普通函數調用須要花費更多時間
  • 應用軟件能夠調用公共函數庫或者使用系統調用

2. 文件和目錄

  • 文件系統是目錄和文件組成的一種層次結構
  • 目錄的起點稱爲根,名稱爲/符號
  • 目錄是包含不少目錄項的文件
  • 邏輯上可認爲每一個目錄項都包含文件名和文件屬性。物理上是不包含的,由於一個文件可被屢次硬連接
  • 文件屬性包括:類型(普通文件,目錄),大小,全部者,權限,修改時間等。state和fstate函數返回文件屬性。

3. 輸入和輸出

3.1 文件描述符

一般是一個小的非負整數,內核用它標識一個特定進程正在訪問的文件服務器

3.2 標準輸入,標準輸出,標準出錯

每當運行一個新程序時,shell都爲其打開三個文件描述符:網絡

說明 文件描述符 頭文件
標準輸入 0 <unistd.h> STDIN_FILENO
標準輸出 1 <unistd.h> STDOUT_FILENO
標準出錯 2 <unistd.h> STDERR_FILENO

3.3 不用緩衝的io

  • 函數open,read,write,lseek,close提供了不用緩衝的io
  • 這些函數都使用文件描述符
  • 頭文件爲<fcntl.h>

3.4 標準io

  • 標準io提供一種帶緩衝io的接口
  • 使用標準io無需擔憂如何選取最佳緩衝區大小,且簡化了堆輸入行的處理
  • 標準io頭文件爲<stdio.h>

4. 程序和進程

4.1 程序

  • 存放在磁盤,處於某個目錄中的可執行文件
  • exec函數執行時,內核將程序讀入存儲器並執行

4.2 進程

  • 程序的執行實例被稱爲進程
  • 每一個進程都有一個惟一的數字標識,稱爲進程ID

4.3 進程控制

進程控制的主要函數:fork,exec和waitpid數據結構

4.4 線程

  • 進程內全部線程共享同一個地址空間,文件描述符,棧,進程相關屬性
  • 線程訪問共享數據時須要採起同步措施避免不一致性
  • 線程也用ID標識,可是隻在它所屬進程內起做用

5. 信號

  • 信號是通知進程已發生某種狀況的一種技術
  • 進程如何處理信號有三種選擇:
    • 忽略該信號
    • 按系統默認方式處理
    • 捕捉該信號:提供一個函數,信號發生時調用該函數。調用signal函數,第一個參數爲信號名稱,第二個參數爲處理函數

6. 時間值

unix系統一直使用兩種不一樣的時間值

  • 日曆時間:UTC時間,用time_t表示。記錄自1970年1月1日以來鎖通過的秒數
  • 進程時間:cpu時間,用clock_t表示。已時鐘滴答計算

二. unix標準化和實現

1. unix標準化

  • ISO c:c語言國際化標準
  • POSIX:可移植的操做系統接口(protable operating system interface)

2. unix實現

  • SVR4:AT&T的UNIX系統實驗室產品,第一版了系統V接口定義
  • BSD:加州伯克利分校研究和開發的,含有AT&T許可證的代碼
  • FreeBSD:BSD去除AT&T許可證代碼後,徹底免費的版本
  • Linux:1991年Linux開發的一款被目前普遍使用的unix操做系統
  • Mac OS:核心系統是Darwin,基於Mach內核和FreeBSD的組合
  • Solaris:sun公司開發的unix系統版本

三. unix提供的文件IO

1. 文件描述符

  • 內核中,全部打開的文件都經過文件描述符引用
  • 打開,新建時,內核向進程返回一個文件描述符
  • 讀寫文件時,將文件描述符傳給read和write

2. open

  • 做用:建立或打開一個文件
  • pathname參數:文件名字
  • flag參數:由如下值進行「或」組成
    • O_RDONLY:只讀
    • O_WRONLY:只寫
    • O_RDWR:讀寫
    • O_APPEND:追加到末尾
    • O_CREATE:文件不存在就建立
    • O_EXCL:同時指定O_CREATE時,若是文件存在,就會出錯。使測試和建立成爲原子操做
    • O_TRUNC:將文件長度截短爲0
    • O_NOCTTY:控制終端相關
    • O_NONBLOCK:非阻塞模式
  • mode參數:文件訪問權限,僅新建文件時使用該參數

3. create

  • 做用:建立文件
  • 等價於
    open(pathname, O_WRONLY|O_CREATE|O_TRUNC, mode)
    複製代碼

4. close

  • 做用:關閉文件
  • 關閉會釋放加在該文件上的全部記錄鎖
  • 進程終止時,內核自動關閉它打開的文件,故能夠不用顯示調用close

5. lseek

  • 做用:設置打開文件的偏移量
  • 默認偏移量爲0,若是設置O_APPEND屬性,默認偏移量爲文件末尾
  • whence的取值:
    • SEEK_SET:設置文件偏移爲pos值
    • SEEK_CUR:設置文件偏移爲當前位置+pos
    • SEEK_END:設置文件偏移爲文件長度+pos

6. read

  • 做用:從打開的文件中讀數據
  • 讀取成功,返回讀到的字節數。讀到末尾,返回0。
  • 致使讀到的字節數小於要求讀字節數的狀況:
    • 普通文件:讀到達到要求字節數時,已經讀到文件結尾了
    • 終端設備文件:一次最多讀一行
    • 網絡數據:緩存區大小小於要讀字節
    • 管道文件:管道包含的字節小於要讀字節

7. write

  • 做用:向打開文件中寫數據
  • 返回值一般與nbyte相同,不然出錯
  • 寫成功後,文件偏移量增長寫入字節數量

9. 文件共享

9.1 打開文件的內核數據結構

unix支持在不一樣進程間共享打開的文件,unix內核使用什麼數據結構來支持這種共享呢?

  • 進程表記錄來全部的進程
  • 每一個進程都有一個記錄項,用來記錄打開文件的文件描述表
  • 文件描述符的每一項包括:
    • 文件描述符標識
    • 指向文件表項的指針
  • 文件表項由內核維護,每一項包括:
    • 文件狀態標識(讀,寫,同步,阻塞等)
    • 當前文件偏移量
    • 指向該文件v節點表項的指針
  • 每一個打開文件都有v節點(v-node)結構,這些信息是打開文件時從磁盤讀入內存的。包括:
    • 文件類型
    • 對此文件進行各類操做的指針
    • i節點信息(索引信息):包括長度,全部者,所在設備,磁盤位置指針等

9.2 兩個獨立進程各自打開同一文件

  • 給定的文件,只有一個v節點表項
  • 每一個進程都有本身的文件表項,以使本身有獨立的文件偏移量

9.3 兩個獨立進程共享同一個文件表項

  • 使用dup和fork函數時,父子進程對於每個文件描述符,都共享同一個文件表項,達到文件共享的目的

9.4 建立共享文件的函數

  • dup:返回的文件描述符爲可用的最小值
  • dup2:返回fieldes2指定的描述符。若是fieldes2已經打開,就關閉。若是fieldes=fieldes2,不關閉,直接返回。
  • fcntl:也能夠建立共享文件

10. 原子操做

  • 原子操做:指多步組成的操做,
  • 任何一個須要調用多個函數的操做都不多是原子操做,由於中間可能會掛起該進程
  • unix提供了一些函數,使多個操做成爲一個「原子操做」
  • O_APPEND標識:lseek和write的原子操做
  • pread:lseek和read的原子操做
  • pwrite:lseek和write的原子操做
  • 調用open時,經過制定O_CREAT和O_EXCL參數,將建立文件做爲原子操做

11. sync, fsync, fdatasync函數

這幾個函數出現的背景:unix提供的延時寫功能,經過提供緩衝區以減小磁盤讀寫次數,可是下降了文件內容更新速度,這幾個函數用於保證緩衝區內容與文件內容的同步,保證一致性。

  • sync:將修改的快緩衝區排入寫隊列,立馬返回,不等待真正寫磁盤
  • fsync:針對指定的文件描述符起做用,且等待磁盤寫完才返回。同步內容包括數據和文件屬性。適用於數據庫系統。
  • fdatasync:包括fsync的功能,可是隻同步數據,不一樣步文件屬性。

12. fcntl函數

  • 做用:改變已打開文件的性質
  • 參數cmd的取值和做用:
    • F_DUPFD:複製一個現有的文件描述符
    • F_GETFD: 設置文件描述符標記
    • F_SETFD: 得到文件描述符標記
    • F_GETFL: 設置文件狀態標記:讀,寫,追加,阻塞等。
    • F_SETFL: 得到文件狀態標記
    • F_GETOWN: 設置異步io全部權
    • F_SEGOWN: 得到異步io全部權
    • F_GETLK:得到記錄鎖
    • F_SETLK:設置記錄鎖
    • F_SETLKW:設置記錄鎖

四. 文件和目錄

1. 文件屬性

1.1 表示文件屬性的數據結構:struct stat

```
struct stat {
    mode_t     st_mode;       //文件模式,包含文件類型,用戶id,組id,訪問權限(9種)等信息
    ino_t      st_ino;       //inode節點號
    dev_t      st_dev;        //設備號碼
    dev_t      st_rdev;       //特殊設備號碼
    nlink_t    st_nlink;      //文件的鏈接數
    uid_t      st_uid;        //文件全部者
    gid_t      st_gid;        //文件全部者對應的組
    off_t      st_size;       //普通文件,對應的文件字節數
    time_t     st_atime;      //文件數據最後被訪問的時間
    time_t     st_mtime;      //文件數據最後被修改的時間
    time_t     st_ctime;      //文件狀態(i節點狀態)的最後修改時間
    blksize_t st_blksize;    //文件內容對應的塊大小
    blkcnt_t   st_blocks;     //偉建內容對應的塊數量
  };
```
複製代碼

1.2 如何獲取文件屬性

  • state:根據文件名獲取屬性
  • fstate:根據描述符獲取屬性
  • lstate:返回符號連接的屬性

1.3 修改屬性的部分方法

  • 訪問時間和修改時間: utime函數,參數爲struct utimbuf,每一項都是utc時間
  • 文件用戶id和組id:chown,fchown,lchown

2. 文件類型:

2.1 st_mode字段控制的文件類型

  • S_ISREG:普通文件。文本或二進制;可執行文件有固定的可被內核識別的格式。
  • S_ISDIR:目錄文件。包含其餘文件的名字以及指向與這些文件有關信息的指針。
  • S_ISBLK:塊特殊文件。提供堆設備(如磁盤)帶緩衝的訪問,訪問長度固定。
  • S_ISCHR:字符特殊文件。提供堆設備(如磁盤)不帶緩衝的訪問,訪問長度不固定。
  • S_ISFIFO:FIFO,命名管道。用於進程間通訊
  • S_ISSOCK:套接字。用於網絡間進程通訊
  • S_ISLINK:符號連接。指向另外一個文件

2.2 stat結構體自己控制的文件類型

  • S_TYPEISMQ:消息隊列
  • S_TYPEISSEM:信號量
  • S_TYPEISSHM:共享存儲對象

3. 文件訪問權限

  • 權限位保存在st_mode屬性中
  • 9個訪問權限位對應的值爲:
  • 更改文件訪問權限的函數:chmod和fchmod

4. UFS文件系統

4.1 磁盤,分區和文件系統圖

  • 一個磁盤分爲多個分區,每一個分區能夠包含一個文件系統
  • i節點是固定長度的記錄項

4.2 詳細的柱面組的i節點和數據塊

  • 每一個柱麪包括:i節點數組,數據庫,目錄塊
  • 每一個i節點包含文件的大部分信息:文件類型,訪問權限,長度,佔用的實際數據庫。(stat結構大多數信息取自i節點)
  • 每一個目錄塊包括:目錄名稱,i節點號
  • 同一個i節點,能夠被不一樣的目錄指向,i節點的連接計數統計指向的數量
  • 文件更名時,實際內容並未移動,只是構造一個新目錄項,指向現有的節點,並解除舊記錄項的連接

5. 硬連接

硬連接直接指向文件的i節點

5.1 建立一個指向現有文件的連接:link方法

  • 若是newpath已經存在,返回出錯
  • 只能建立newpath中最後一個份量,路徑中其餘部分必須已經存在
  • 不少文件系統不容許堆目錄建立硬連接
  • 超級用戶能直接建立目錄硬連接

5.2 刪除一個現有的連接項:unlink方法

  • 將path所引用的文件的連接數減1
  • 只有當鏈接技術爲0,該文件的內容才被刪除
  • 對於文件,可使用remove功能,和unlink同樣
  • 對於目錄,可使用rmdir功能,和unlink同樣

6. 符號連接

符號連接是指向一個文件的間接指針。

6.1 符號連接是爲了避開硬連接的一些限制

  • 硬連接要求連接和文件位於同一文件系統中
  • 只有超級用戶才能建立指向目錄的硬連接

6.2 使用符號連接須要注意的事情

  • 當調用某個函數時,須要注意函數處理的是連接的文件,仍是連接自己

6.3 符號連接相關的函數

  • 建立符號連接: symlink
  • 打開符號連接:readlink

7. 目錄

  • 建立目錄:mkdir
  • 刪除目錄:rmdir。入爐連接計數爲0,且沒有進程打開次目錄,釋放目錄空間。
  • 讀取目錄:
  • 更改當前工做目錄:chdir,fchdir

五. 標準IO

  • 標準io庫不只在unix上,不少操做系統上都實現了。
  • 標準io處理不少細節,例如:緩衝區分配,優化長度執行io等。便於用戶使用。
  • 使用的頭文件爲<stdio.h>。
  • 標準io的底層調用了前面介紹的unix內核io。
  • 標準io的缺點是效率低。這與它須要複製的數據量有關

1. 流和File對象

  • unix內核io提供的io函數都是針對文件描述符的
  • 可是標準io的操做是針對流進行的
  • 標準io文件流可用於單字節或寬字節字符集,由流定向決定(fwide函數)。
  • 標準io打開一個文件(fopen函數)時,返回一個FILE的指針,它包含了實際io的文件描述符,指向用於該流緩衝區的指針,緩衝區長度,緩衝區當前字符數,出錯標誌,文件結束標誌等信息
  • 每一個進程預約義三個流:標準輸入,標準輸出,標準出錯

2. 緩衝

2.1 緩衝類型

標準io提供三種類型的緩衝

  • 全緩衝:填滿標準io緩衝區後才進行實際的io操做(malloc申請緩衝區,flush執行寫操做)。
  • 行緩衝:輸入輸出中遇到換行符時進行實際的io操做。涉及終端設備時,一般用行緩衝。
  • 不帶緩衝:不對字符進行緩衝存儲。標準出錯流一般不帶緩衝。

2.2 設置緩衝類型

  • setbuf
  • setvbuf:第三個參數:
    • _IOFBF:全緩衝
    • _IOLBF: 行緩衝
    • _IONBF:無緩衝

3. 打開流

  • fopen:打開一個指定的文件
  • freopen:將一個文件讀到一個指定的流。若是流已經打開,就先關閉,已經定向,就先清除定向。
  • fdopen:經過文件描述符打開文件。由於管道和網絡通訊等特殊文件不能用標準io函數fopen打開,因此用到該函數。
  • type:指定文件的打開方式

4. 讀和寫流

讀寫流有三種不一樣的方式

  • 每次讀寫一個字符:
    • 讀:getc,fgetc,getchar
    • 寫:putc,fputc,putchar

    不帶f前綴的從標準輸入流讀取數據,帶f前綴的從指定流讀取數據。不帶f前綴的函數不推薦使用,由於它不指定緩衝區大小,會致使溢出。

  • 每次讀寫一行:
    • 讀:gets,fgets
    • 寫:puts,fputs
  • 每次讀寫必定數量的對象(直接io,二進制io):
    • 讀:fread,須要指定要讀取的元素個數和每一個元素的大小
    • 寫:fwrite
    • 缺點:不一樣系統間,交換二進制數據會編譯期和計算機體系結構不一樣而有差別,因此必須用更高級的協議。

5. 定位流

定位標準io流有三種不一樣的方式

  • ftell(獲取),fseek(設置):long類型的文件位置
  • ftello和fseeko:off_t類型的文件位置
  • fgetpos和fsetpos:fpos_t的抽象數據類型表示文件位置

6. 格式化io

6.1 格式化輸出

  • printf:格式化數據寫到標準輸出
  • fprintf:格式化數據到指定流
  • sprintf:格式化的數據送入數組buf中,尾部自動加入null。可能會致使緩衝區溢出,需調用者本身保證
  • 轉換說明以%開始

6.2 格式化輸入

六. 系統數據文件

1. 口令文件

  • 存放目錄:/etc/passwd
  • 數據結構:<pwd.h>中的passwd結構體
  • 查看指定用戶口令的函數接口:
  • 查看全部用戶口令的函數接口:

2. 陰影文件(加密口令)

  • 存放目錄:/etc/shadow
  • 查看的接口:

3. 組文件

  • 存放目錄:/etc/group
  • 數據結構:<grp.h>中的group
  • 查看指定組:
  • 查看全部組:

4. 其餘數據文件

  • 服務器提供服務的數據文件:/etc/services
  • 記錄協議信息的數據文件:/etc/protocols
  • 記錄網絡信息的數據文件:/etc/networks

5. 登錄帳號文件

  • 當前登錄進系統的用戶:/var/run/utmp
  • 跟蹤登錄和註銷信息:/var/log/wtmp

6. 獲取系統信息

  • 獲取主機與操做系統相關信息
  • 只獲取主機名

7. 時間格式

  • 日曆時間(UTC時間)
  • 更高精度的時間
  • 各類時間的轉化關係
相關文章
相關標籤/搜索