Linux 中必須要了解的命令操作
導讀 | 檔案是 中的一個重要概念。在Linux中,一切(幾乎一切)都是檔案。簡單的說,C中基本的的printf()函式,scanf()函式,其實都屬於檔案操作。 |
對於檔案操作,雖然都是透過函式呼叫的方式實現,卻還是能分為兩類:系統呼叫和庫函式。
這篇文章將先介紹Linux中檔案的概念,系統呼叫和庫函式的概念 ,然後具體的討論兩種方式下的檔案操作。
博文的主要內容如下:
- Linux 中的檔案
- 檔案訪問-庫函式
- 檔案訪問-系統呼叫
- 庫函式
- 標準 I/O 庫
- /proc檔案系統
按照普通的定義,檔案不過是一堆資料,在往下說,就是儲存器中的010101...而我們這裡討論的檔案有了更廣的定義。對於Linux中的檔案,我的理解是:
Linux中的檔案具有的特點是:可透過作業系統或者程式對外提供資訊,也能對內輸入資訊,可以被建立,刪除。
Linux中,檔案有特別重要的意義,他們為作業系統和裝置提供了一個簡單而統一的介面。在Linux中,幾乎一切都可以看做是檔案 。
這就意味著,普通程式完全可以像使用檔案(普通定義)那樣使用磁碟檔案、序列口、印表機和其他裝置。
硬體裝置在linux作業系統中也被表示為檔案。例如,可以透過如下 把cd-rom驅動器掛載為一個檔案,
#mount -t iso9660 /dev/hdc /mnt/cdrom
#cd /mnt/rom
然後,就能像訪問普通檔案那樣在cd-rom目錄中漫遊。
和操作一般意義上的檔案一樣,linux中對檔案的操作只需要五個基本的函式:
open、close、read、write和ioctl
透過呼叫這幾個函式就能對Linux中的檔案進行讀、寫等操作。不過,這種操作又分為系統呼叫和庫函式呼叫。簡單的說,系統呼叫是最直接的方式,
庫函式呼叫最終也是透過系統呼叫實現的。可認為庫函式呼叫是對系統調出於效率考慮而做出的最佳化。
庫函式呼叫和系統呼叫的區別和聯絡請參看: 呼叫和庫函式呼叫的區別
我們用很少的函式就可以對檔案和裝置進行訪問和控制。這些函式就是所謂的系統呼叫,由作業系統直接提供,他們是通向作業系統本身的介面。
作業系統的核心部分,既核心,其實就是一組裝置驅動程式。這是一些對硬體進行控制的介面。
透過系統呼叫來訪問檔案是最直接的方式。系統呼叫函式直接作用於作業系統核心的裝置驅動程式從而實現檔案訪問。
在系統中需要處理的檔案(讀、寫操作)需要一個標識,以便在其它地方能識別出這個檔案,於是就產生了檔案描述符。檔案描述符是一些小值整數,簡單的說就是
一個檔案ID用於在系統中唯 一的標識檔案。檔案描述符的總數也就是系統可以開啟檔案的最多個數,這取決於系統的配置情況。
當開始執行程式時,也就是系統開始執行時,它一般會有三個已經開啟的檔案描述符。他們是:
- 0:標準輸入
- 1:標準輸出
- 2:標準錯誤
其它檔案的檔案描述符,在呼叫檔案開啟函式open時返回。這就是說,每個裝置對應著一個檔案描述符。檔案描述符由作業系統分配,每次分配最小的。
write,就是把緩衝區的資料寫入檔案中。注意,這裡的檔案時廣泛意義的檔案,比如寫入磁碟、寫入印表機等等。
Linux 中write()的函式原型:
size_t write(int fildes, const void *buf, size_t nbytes);
引數說明:
fildes:檔案描述符,標識了要寫入的目標檔案。例如:fildes的值為1,就像標準輸出寫資料,也就是在螢幕上顯示資料;如果為 2 ,則想標註錯誤寫資料。
*buf:待寫入的檔案,是一個字串指標。
nbytes:要寫入的字元數。
函式返回值:size_t 返回成功寫入檔案的字元數。需要指出的是,write可能會報告說他寫入的位元組比你所要求的少。這並不一定是個錯誤。在程式中,你需要檢查
error已發現錯誤,然後再次呼叫write寫入剩餘的資料。
請看下面的例子:
執行結果:
這個程式只在標準輸出上顯示一條訊息。
系統呼叫read是從檔案中讀出資料。要讀取的檔案用檔案描述符標識,資料讀入一個事先定義好的緩衝區。他返回實際讀入的位元組數。
Linux中read的函式原型:
size_t read(int fildes, void *buf, size_t nbytes);
引數說明:
fildes:檔案描述符,標識要讀取的檔案。如果為0,則從標準輸入讀資料。類似於scanf()的功能。
*buf:緩衝區,用來儲存讀入的資料。
nbytes:要讀取的字元數。
返回值:size_t返回成功讀取的字元數,它可能會小於請求的位元組數。
執行結果:
系統呼叫open的作用是開啟一個檔案,並返回這個檔案的描述符。
簡單地說,open建立了一條到檔案或裝置的訪問路徑。如果操作成功,它將返回一個檔案描述符,read和write等系統呼叫使用該檔案描述符對檔案或
裝置進行操作。這個檔案描述符是唯 一的,他不會和任何其他執行中的程式共享。如果兩個程式同時開啟一個檔案,會得到兩個不同的問價描述符。如果
同時對兩個檔案進行操作,他們各自操作,互補影響,彼此相互覆蓋(後寫入的覆蓋先寫入的)為了防止檔案按讀寫衝突,可以使用檔案鎖的功能。這不是
本次重點,以後介紹。
Linux中open的函式原型有兩個:
int open(const char *path, int oflags);
int open(const char *path, int oflags, mode_t mode );
引數說明。
path:準備開啟的檔案或裝置名字。
oflags:指出要開啟檔案的訪問模式。open呼叫必須指定如下所示的檔案訪問模式之一:
open呼叫哈可以在oflags引數中包括下列可選模式的組合(用”按位或“操作):
- O_APPEDN: 把寫入資料追加在檔案的末尾。
- O_TRUNC: 把檔案長度設為零,丟棄以後的內容。
- O_CREAT: 如果需要,就按引數mode中給出的訪問模式建立檔案。
- O_EXCL: 與O_CREAT一起呼叫,確保呼叫者建立出檔案。使用這個模式可防止兩個程式同時建立一個檔案,如果檔案已經存在,open呼叫將失敗。
關於其他可能出現的oflags值,請看考open的呼叫手冊。
mode:
當使用哦、O_CREAT標誌的open來建立檔案時,我們必須使用三個引數格式的open呼叫。第三個引數mode 是幾個標誌按位OR後得到的。他們是:
- S_IRUSR: 讀許可權,檔案屬主。
- S_IWUSR:寫許可權,檔案屬主。
- S_ IXUSR:執行許可權,檔案屬主。
- S_IRGRP:讀許可權,檔案所屬組。
- S_IWGRP:寫許可權,檔案所屬組。
。。。。
請看下面例子:
open("myfile", O_CREAT, S_IRUSR|S_IXOTH ;
他的作用是建立一個名為myfile 的檔案,檔案屬主擁有讀許可權,其他使用者擁有執行許可權,且只有這些許可權。
執行結果:
程式建立了一個名為myfile的檔案,檔案屬主有讀許可權,其他使用者有執行許可權,且只有這些許可權。
close系統呼叫用於“關閉”一個檔案,close呼叫終止一個檔案描述符fildes以其檔案之間的關聯。檔案描述符被釋放,並能夠重新使用。
close成功返回1,出錯返回-1.
#Include<unistd.h>
int close(int fildes);
ioctl提供了一個用於控制裝置及其描述符行為和配置底層服務的介面。終端、檔案描述符、甚至磁帶機都可以又為他們定義的ioctl,具體
細節可以參考特定裝置的使用手冊。
下面是ioctl 的函式原型
#include<unistd.h>
int ioctl(int fildes, int cmd,,,,,,);
ioctl對描述符fildes指定的物件執行cmd 引數中所給出的操作。
還有許多其他的系統呼叫能對檔案進行操作。
幾個常用的如:lseek()對檔案描述符fildes指定檔案的讀寫指標進行設定,也就是說,它可以設定檔案的下一個讀寫位置。
fstat,stat,lstat 是和檔案描述符相關的函式操作,這裡就不做介紹。
dup,dup2系統呼叫。dup提供了複製檔案描述符的方法,使我們能夠透過兩個或者更多個不同的檔案描述符來訪問同一個檔案。這可以用於
在檔案的不同位置對資料進行讀寫。
在輸入、輸出操作中,直接使用系統呼叫效率會非常底。具體原因有二:
- 1.系統呼叫會影響系統效能。與函式呼叫相比,系統呼叫的開銷大。因為在執行系統呼叫的時候,要切換到核心程式碼區執行,然後再返回使用者程式碼。這必然就需要大量的時間開支。一種解決辦法是:儘量減少系統呼叫的次數,讓每次系統呼叫完成儘可能多的 任務。例如每次系統呼叫寫入大量的字元而不是單個字元。
- 2.硬體會對系統呼叫一次能讀寫的資料塊做一定的限制。例如,磁帶機通常的寫運算元據塊長度是10k,如果縮寫資料不是10k的整數倍,磁帶機還是會以10k為單位繞磁帶,這就在磁帶上留下空隙。
為了提高檔案訪問操作的效率,並且使得檔案操作變得更方便,Linux發行版提供了一系列的標準函式庫。他們是一些由函式構成的集合,你可以在自己的程式方便的中使用它們,
去操作檔案。提供輸出緩衝功能的標準I/O庫就是這樣的例子。你可以高效的寫任意長度的資料塊,庫函式則在需要的時候安排底層函式呼叫(系統呼叫)
也就是說,庫函式在使用者和系統之間,增加了一箇中間層。如下圖所示:
庫函式是根據實際需要而包裝好的系統呼叫,使用者可在程式中方便的使用庫函式,如標準I O庫(稍後會講)
標準I/O庫及其標頭檔案<stdio.h>為底層I/O系統呼叫提供了一個通用的介面。這個庫現在已經成為ANSI標準C的一部分,而前面所講的系統呼叫卻不是。
標準I/O庫提供了許多複雜功能的函式,用於格式化輸出和掃描輸入,它還負責滿足裝置的緩衝需求。
在許多方面,使用標準I/O庫和使用底層檔案描述符類似。需要先開啟一個檔案,已建立一個檔案訪問路徑(也就是系統呼叫中的檔案描述符)
在標準I/O庫中,與檔案描述符對應的叫 流(stream),它被實現為指向結構FILE的指標。
在啟動程式時,有三個檔案流是自動開啟的。他們是:
- stdin: 標準輸入
- stdout: 標準輸出
- stderr: 標準錯誤輸出
下面會介紹一些常用的I/O庫函式:
fopen函式類似於系統呼叫中的open函式。和open一樣,它返回檔案的識別符號,只是這裡叫做流(stream),在庫函式里實現為一個指向檔案的指標。
如果需要對裝置的行為進行明確的控制,最好使用底層系統呼叫,因為這可以避免使用庫函式帶來的一些非預期的副作用,如輸入/輸出緩衝。
函式原型:
#include<stdio.h>
FILE *fopen(const char *filename, const char *mode);
引數說明:
*filename:開啟檔案的檔名
*mode:開啟的方式
r 以只讀方式開啟檔案,該檔案必須存在。
r+ 以可讀寫方式開啟檔案,該檔案必須存在。
rb+ 讀寫開啟一個二進位制檔案,允許讀資料。
rw+ 讀寫開啟一個文字檔案,允許讀和寫。
w 開啟只寫檔案,若檔案存在則檔案長度清為0,即該檔案內容會消失。若檔案不存在則建立該檔案
w+ 開啟可讀寫檔案,若檔案存在則檔案長度清為零,即該檔案內容會消失。若檔案不存在則建立該檔案。
fopen在成功是返回一個非空的FILE *指標。失敗返回NULL
fread函式從檔案流中讀取資料,對應於系統呼叫中的read;fwrite函式從檔案流中寫資料,對應於系統呼叫中的write
函式原型:
#include<stdio.h>
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
引數說明:
*ptr 要讀取資料的緩衝區,也就是要存放讀取資料的地方。
size:指定每個資料記錄的長度。
nitems: 計數,給出要傳輸的記錄個數。
返回值:成功讀取到資料緩衝區的記錄個數,當到達檔案尾時,他的返回值可能會消耗與nitems,甚至可以是0
size_t fwrite(const coid *ptr, size_t size , size_t nitimes, FILE *stream);
他從指定的資料緩衝區ptr中把資料寫入檔案流,返回成功寫入的記錄個數。
fclose函式關閉指定的檔案流stream,這個操作會使所有未寫出的資料都寫出。因為stdio庫函式會對資料進行緩衝,所有呼叫fclose函式是很重要的。
如果程式需要確保資料已經全部寫出,就應該呼叫fclose函式。雖然程式正常結束時,也會自動的呼叫fclose函式,但這樣就不能檢測出呼叫fclose所產生的錯誤了。
函式原型如下:
#include<stdio,h>
int fclose(FILE *stream);
fflush函式的作用是把檔案流中所有未寫出的資料全部寫出。 處於效率考慮,在使用庫函式的時候會使用資料緩衝區,當緩衝區滿的時候才進行寫操作。使用fflush函式
可以將緩衝區的資料全部寫出,而不關心緩衝區是否滿。fclose的執行隱含呼叫了fflush函式,所以不必再fclose執行之前呼叫fflush。
函式原型:
#include<stdio.h>
int fflush(FILE *stream);
Linux將一切看做檔案,硬體裝置在檔案系統中也有相應的條目。/dev目錄中的檔案使用底層系統呼叫這樣一種特殊方式來訪問硬體。
/proc檔案系統,可以看做是一個特殊的檔案系統,在這個系統中,每個檔案都對應一個獨立的硬體,所以使用者可以透過proc檔案系統像訪問檔案一樣來訪問硬體裝置。
該檔案系統通常表現為/proc 目錄。該目錄中包含了許多特殊檔案以允許對驅動和核心資訊進行高層訪問。
如果你想知道CPU的資訊,核心版本資訊等,就可以透過proc檔案系統。
/proc目錄中的檔案會隨系統的不同而不同。我的電腦上的/proc 中的檔案如下所示:
在多數情況下,直接讀取這些檔案就可以獲得狀態資訊。
例如,獲取CPU的資訊:
記憶體使用資訊(只顯示裡區域性~):
每次讀這些檔案的內容時,他們所提供的資訊都會及時更新。所以再讀一次meminfo檔案會得到不同的結果。
由特定核心函式給出的更多資訊可以在proc目錄的子目錄中查到。
例如:檢視網路套接字的使用統計:
用ps 可得到當前正在執行的程式,每個程式在proc中都有相應的資訊檔案,透過檢視這個檔案,可以得知程式相關的資訊:
程式2754的當前工作目錄是:/hme/yyl
程式 /bin/su正在執行,還有其他資訊此處不再說明;
例如,系統中所有執行的程式同時開啟的檔案總數是Linux核心的一個引數。
如果我們想要增大這個歌值,則可透過寫同一個檔案來實現。
注意:對proc的寫操作要注意許可權問題,在修改時要小心,不適當的值可能會影響到系統的一執行。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2943136/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 運維人員必須要了解熟知的Linux命令彙總運維Linux
- 必須掌握的10個Linux命令!Linux
- 學習Linux必須掌握的命令!Linux
- shell程式設計必須要掌握的命令-xargs程式設計
- 【Linux常用命令①】程式設計師必須掌握的Linux命令Linux程式設計師
- Linux下必須知道的網路命令都有哪些?Linux
- 學習Linux必須掌握的命令!經驗分享Linux
- Linux 操作必備 150 個命令Linux
- 測試人員為什麼必須要會 LinuxLinux
- Linux系統中必須掌握的特殊字元!Linux字元
- 必須要掌握的重要目錄
- Linux新手入門必須要掌握的10個知識點!Linux
- 程式設計師必須要了解的web安全程式設計師Web
- 對於MySQL你必須要了解的鎖知識MySql
- 學習web前端你必須要了解的主流框架!Web前端框架
- JavaScript必須要掌握的知識-作用域JavaScript
- 為什麼技術必須要學習Linux?Linux發展趨勢如何?Linux
- 必須要會的 50 個 React 面試題React面試題
- 學習web前端,必須要掌握的CSS原理Web前端CSS
- 面試前必須知道的MySQL命令【explain】面試MySqlAI
- 必須掌握的Linux使用者組Linux
- Git中~你必須掌握的!Git
- 短影片app開發中存在的哪些要點是必須明確的?APP
- 人工智慧要普及,這一步必須要先行!人工智慧
- 必須要會回答的Java面試題(字串篇)Java面試題字串
- C語言必須要記住的經典程式C語言
- 進大廠必須要會的單元測試
- Java程式設計生涯你必須要了解的資料結構Java程式設計資料結構
- 使用微服務前必須要了解的“分散式系統的謬誤”微服務分散式
- 【面試篇】寒冬求職季之你必須要懂的原生JS(中)面試求職JS
- go中Slice的一些使用方式與必須要懂的使用事項Go
- 學習Kali Linux必須知道的幾點Linux
- Linux必須掌握的shell指令碼基礎Linux指令碼
- CSS中那些必須掌握的概念CSS
- Linux系統中firewalld防火牆常用的操作命令Linux防火牆
- 檔案管理,你必須要知道的三個要點
- JavaScript必須要掌握的知識-作用域編寫提升JavaScript
- java開發必須要掌握的20個核心技術Java