Linux之基礎I/O

目錄

一、C語言中的文件操作

二、系統文件操作I/O

三、文件描述符fd

1、文件描述符的引入

2、對fd的理解

3、文件描述符的分配規則

四、重定向??

1、重定向的原理

2、重定向的系統調用dup2

五、Linux下一切皆文件


一、C語言中的文件操作

1、打開和關閉?

在C語言的文件操作中,我們要對一個文件進行寫入和讀寫的前提是打開文件。我們使用fopen來打開文件,打開失敗將會返回NULL ,而打開成功則返回文件的指針 FILE*。最后要進行的操作就是關閉(fclose)文件

函數原型:FILE *fopen(const char *path, char *mode)。path為文件名(也可以是文件路徑),mode為打開方式,它們都是字符串。

int fclose(FILE *fp)。

下面我們來看一看下面的代碼:

上面的代碼中,我打開了一個文件log.txt。但是我的當前目錄下并沒有這個文件。?

這個文件并不存在,但是我們要使用,那么fopen會在當前路徑下給我們創建出這個文件。那么這個當前路徑是什么呢??

簡單來說,當前路徑:一個進程運行起來的時候,每個進程都會去記錄自己當前所處的工作路徑。所以當前路徑也就是當前進程的工作路徑。

有了這個概念,我們就能理解了:test.c形成的可執行程序在運行后,會成為一個進程,該進程會通過調用系統接口幫助我們創建文件,因此新文件所在的路徑就是當前進程的工作路徑。

第一個紅色方框就是當前進程的工作路徑,exe就是當前的可執行文件。第二個紅色方框就是表示執行的是進程工作路徑下的那個可執行程序。

注:單純以w方式打開文件,會自動清空文件原有的數據。r+(讀寫)代表文件不存在則出錯,w+(讀寫)代表文件不存在則創建。(帶有+的表示讀寫)。a代表向文件中追加內容。

2、讀寫文件

我們知道在C語言中,我們可以通過fgets和fputs以字符串形式進行讀寫,也可以通過fprint和fscanf進行格式化讀寫。(下面的函數在C語言中我們已經學過了,這里就不一一演示了)。

int fputs (const char * str, FILE * stream )
char * fgets (char * str, int num, FILE * stream )
int fprintf (FILE * stream, const char * format, ... )
int fscanf (FILE * stream, const char * format, ... )

二、系統文件操作I/O

操作文件,除了上述C接口(當然,C++也有接口,其他語言也有),我們還可以采用系統接口來進行文件訪問。其實真正能夠直接訪問文件的只有操作系統,而各種編程語言能夠訪問文件的函數的本質都是去調用了操作系統提供的各種系統接口。

1、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:打開文件名

flags : 標志位。(打開文件時,可以傳入多個參數選項,用一個或者多個常量進行“或”運算,構成 flags)?

O_RDONLY:只讀打開? ? ? ? O_WRONLY : 只寫打開? ? ? ? ?O_RDWR : 讀寫打開

O_CREAT : 若文件不存在,則創建它。需要使用mode選項,來指明新文件的訪問權限

O_APPEND : 追加寫

O_TRUNC:打開時,清空文件內容。

返回值:成功:新打開的文件的文件描述符? ? ? ? ?失敗:-1

~ 使用比特位傳遞選項

但是,flags是一個整型,他只表示一個參數,那么我們是怎么通過flags傳入多個參數呢?這里我們使用了一種數據結構叫做比特位:一個整數有32個比特位,所以我們可以通過比特位來傳遞選項。

下面我們通過一個例子,來看看是怎么實現的。

因此,我們可以使用 | (或)來幫助我們傳遞多個參數,以此實現不同的功能。?

mode參數

如果你使用O_CREAT參數創建一個新的文件,那么你還可以通過第三個參數mode來設置該文件的權限。

2、close

//所在頭文件
#include <unistd.h>//原型
int close(int fd);

3、read和write

文件打開后,我們就業對文件進行讀取或者寫入了。

write:寫入

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

fd:要寫入的文件? ? ? ? buf:要寫入的內容? ? ? ?count:所寫內容的大小。?

read:讀取

//頭文件
#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);

fd:要讀取的文件? ?buf:存放讀取內容的數組? ? count:讀取的內容大小?

三、文件描述符fd

我們通過上面的學習,發現,open的返回值是一個整型,其實這個整型其實就是代表文件描述符fd。

1、文件描述符的引入

我們來看看下面的代碼

運行結果如下

我們知道fd是一個整型了,那么為什么是從3開始的呢?那0,1,2跑哪里去了呢?

在C語言階段,我們知道在程序運行時,操作系統會默認打開三個標準輸入輸出流:標準輸入,標準輸出,標準錯誤。對應到C語言當中就是stdin、stdout以及stderr。在C++中則是cin、cout、cerr,而在其他的語言中也有相應的輸入輸出流。

我們知道C語言中的stdin、stdout以及stderr這三個家伙實際上都是FILE*類型的,并不是int類型。因為FILE*是一個結構體指針,是C語言進行了封裝的,是為了方便用戶使用。而在操作系統層面,比如在Linux下,只認fd,而且只有操作系統才能直接訪問文件,那么各種語言為了既方便用戶使用,又要遵循操作系統的規則,必定在FILE結構體里面封裝了fd,這樣才能在系統層面去使用文件。

所有各種語言都有封裝自己的輸入輸出流,實際上這種特性并不是某種語言所特有的,而是由操作系統所支持的。

那么,說到這里,我們已經有一點感覺了,0,1,2哪去了呢?會不會是分別代表著標準輸入,標準輸出、標準錯誤呢?答案是肯定的。在Linux下0,1,2就是表示這個意思。

那么我們也就能夠理解了,0,1,2所表示的文件操作系統已經幫我們打開了!

下面通過代碼來驗證一下:

所以說,在系統層面,我們只能用0,1,2,3等整數來確定一個文件。?

2、對fd的理解

進程想要訪問文件,那么要先打開文件。而文件是由進程運行時打開的,一個進程可以打開多個文件,而系統當中又存在大量進程,也就是說,在系統中任何時刻都可能存在大量已經打開的文件。所以操作系統務必要對這些已經打開的文件進行管理。那么怎么進行管理呢?先描述,再組織!

操作系統會為每個已經打開的文件創建各自的struct file結構體(其中包含了該文件幾乎全部的內容),然后將這些結構體以雙鏈表的形式連接起來,之后操作系統對文件的管理也就變成了對這張雙鏈表的增刪查改等操作。

所以,為了區分被打開的文件各自屬于那個進程,操作系統必定會將進程與文件之間建立某種聯系。

那么進程和文件是怎么建立聯系的呢?

首先,我們來想一想fd為什么是連續的整數呢?我們學過的知識中有什么是和連續的整數有關且從0開始的呢?我們很容易就可以想到一個——數組的下標!沒錯,fd就是數組的下標!那么是什么數組的下標呢?

我們知道,當一個程序運行起來時,操作系統會將該程序的代碼和數據加載到內存,然后為其創建對應的task_struct,task_struct中的一個指針變量指向該進程的mm_struct(進程地址空間),通過頁表建立虛擬內存和物理內存之間的映射關系。

而task_struct當中有一個指針,該指針指向一個名為files_struct的結構體,在該結構體當中就有一個名為fd_array的指針數組,該數組的下標就是我們所謂的文件描述符。

當進程打開一個文件時,該文件從磁盤當中加載到內存,形成對應的struct file,OS將該struct file連入文件雙鏈表,并將該結構體的首地址填入到fd_array數組當中下標為3的位置,使得fd_array數組中下標為3的指針指向該struct file,最后返回該文件的 fd 給進程。

所以,我們只要有某一文件的文件描述符,就可以找到該文件相關的內容,進而對文件進行一系列輸入輸出操作。?

3、文件描述符的分配規則

一般情況下,操作系統默認為進程打開標準輸入,輸出,錯誤,分別對應fd為0,1,2。所以0,1,2位置已經被占用了,所以只能從3開始進行分配。之后打開的文件按順序fd為3,4,5 ......

若我們在打開新的文件前,先關閉文件描述符為0的文件,此后文件描述符的分配又會是怎樣的呢?

結果如下:

可以看到,新打開的文件獲取到的文件描述符變成了0。

我們再多打開幾個文件:

結果如下:第一個打開的文件獲取到的文件描述符變成了0,而之后打開文件獲取到的文件描述符還是從3開始依次遞增的。

所以:文件描述符是從最小但是沒有被使用的fd_array數組下標開始進行分配的。

四、重定向??

1、重定向的原理

~ 輸出重定向

運行結果如下:

根據運行結果,我們發現printf函數本應該將結果輸出到顯示器(標準輸出)讓我們看見,但是結果并沒有在顯示器上顯示出來,但是結果卻被打印到了 log.txt 里面。 這就是我們所說的輸出重定向。

輸出重定向:將我們本應該輸出到一個文件的數據重定向輸出到另一個文件中。

具體原理如下圖:

close的本質其實是將進程和文件的關聯關系解除。close(1)就是將1位置的指針設成NULL,但是語言層的 stdout(或者cout等)指向的是一個struct FILE類型的結構體,結構體中存儲文件描述符的變量的值仍然是1。

接著創建了一個新的文件log.txt,從0開始遍歷數組,發現1位置為空,所以將1位置的指針指向log.txt,這就建立了新的關聯關系。

所以當你使用C語言的printf向stdout寫入的時候,stdout的fd仍然是1,但是底層的1位置已經指向log.txt了,所以就寫到了log.txt里面。

~ 追加重定向

追加重定向就是在輸出重定向的基礎上,將“清空”的參數改成“追加”的參數。

2、重定向的系統調用dup2

上面是我們根據文件描述符的分配規則,來進行重定向的。下面我們使用系統調用接口dup2來幫助我們實現重定向。

功能: dup2會將fd_array[oldfd]的內容拷貝到fd_array[newfd]當中,如果有必要的話我們需要先使用關閉文件描述符為newfd的文件。?

返回值: dup2如果調用成功,返回newfd,否則返回-1。

我們使用下面的代碼舉例:

五、Linux下一切皆文件

廣義上的文件:站在操作系統Linux的角度,能夠被input讀取,或者能夠被output寫出的設備就叫做文件。

所以,顯示器、鍵盤、網卡、顯卡、磁盤等,幾乎所有的外設都可以稱為文件。

在Linux下,我們將文件分為:1、內存文件(文件已經打開,已經加載到了內存中)2、磁盤文件(文件還沒有被打開,沒有被加載到內存中)。

那么Linux下一切皆文件具體是怎么體現的呢?

首先,Linux內核是用C語言寫的。每個外設的硬件結構是不一樣的,那么我們通過操作系統訪問外設的方式肯定是不一樣的。但是,操作系統僅僅通過提供四個系統調用(open,close,write,read),就可以幫助用戶訪問顯示器、磁盤等文件。那么看似相同的方法是怎么訪問不同的硬件設備的呢?

我們在學習了C++或者Java等能夠面向對象的編程語言后,我們知道可以使用類來描述一個文件,然后使用多態達到使用相同接口而產生不同效果,所以這些語言可以做到上面的事。可是,Linux內核是使用C語言寫的,C語言可是沒有面向對象的特點的,也沒有多態的概念,那么它是怎么做到的呢?

任何一個被打開的文件的有自己的結構體對象struct file{ //各種文件的屬性 },不同的文件對應的讀寫方法不一樣,struct file對象里面可以有很多的(*readp)()、(*writep)()函數指針,通過函數指針指向具體的讀寫方法。

這樣,用戶就可以不用關心底層差別,統一使用文件的接口方式進行文件操作。

所以,在Linux下,一切皆文件!?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/542492.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/542492.shtml
英文地址,請注明出處:http://en.pswp.cn/news/542492.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

moore和mealy_Mealy機和Moore機的比較研究 目錄

moore和mealyFinite automata may also have outputs corresponding to each input symbol. Such finite automata are known as finite automata with the output. 有限自動機還可以具有與每個輸入符號相對應的輸出。 這種有限自動機稱為輸出的有限自動機。 There are two fi…

oracle sys連接不上,oracle – 為什么我不能在SYS擁有的對象上創建觸發器?

在嘗試創建名為ghazal_current_bef_upd_row的觸發器時&#xff1a;create trigger ghazal_current_bef_upd_rowbefore update on ghazal_currentfor each rowwhen (new.Rating < old.Rating)begininsert into ghazal_current_audit(GhazalName,Old_Rating,New_Rating)values…

大一python編程題_請教python編程問題(作業就剩這幾道題了)

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓1. def cleanword(word):(用Python寫出程序&#xff0c;使程序可以通過下面的doctest)""">>> cleanword(what?)what>>> cleanword("now!")now>>> cleanword(?"word!,$…

Linux筆記1-5 --用戶

## 1 ## 用戶理解用戶就是系統使用者的身份在系統中用戶存儲為若干竄字符若干個系統配置文件用戶信息涉及到的系統配置文件&#xff1a;/etc/passwd ###用戶信息用戶&#xff1a;密碼&#xff1a;uid&#xff1a;gid&#xff1a;說明&#xff1a;家目錄&#xff1a;用戶使用…

python運維開發培訓_運維架構師-Python 自動化運維開發-014

運維架構師-Python 自動化運維開發-014九、標準數據類型1、為什么編程語言中要有類型類型有以下幾個重要角色&#xff1a;對機器而言&#xff0c;類型描述了內存中的電荷是怎么解釋的。對編譯器或者解釋器而言&#xff0c;類型可以協助確保上面那些電荷、字節在程序的運行中始終…

JavaScript | 演示函數中按值調用的示例

Here, we are designing a function named change() that has an argument and we are trying to change the value of the passed argument inside the function, but it will not effect to the main/actual argument that is passed as the argument while calling. 在這里&…

機器視覺支架制作(帶效果測試)

圖像處理系統中&#xff0c;鏡頭、光源的選配&#xff0c;對于最后能否產生穩定的識別效果至關重要。而搭載鏡頭、光源的是支架。機器視覺的支架一般都是根據項目的具體需要進行配置的&#xff0c;搜索淘寶能夠得到一些商品。 這些支架形狀不一&#xff0c;價格在數百元到千元之…

c語言中將整數轉換成字符串_在C語言中將ASCII字符串(char [])轉換為十六進制字符串(char [])...

c語言中將整數轉換成字符串Given an ASCII string (char[]) and we have to convert it into Hexadecimal string (char[]) in C. 給定一個ASCII字符串(char [])&#xff0c;我們必須在C中將其轉換為十六進制字符串(char [])。 Logic: 邏輯&#xff1a; To convert an ASCII …

redis rdb aof區別_理解Redis的持久化機制:RDB和AOF

什么是Redis持久化?Redis作為一個鍵值對內存數據庫(NoSQL)&#xff0c;數據都存儲在內存當中&#xff0c;在處理客戶端請求時&#xff0c;所有操作都在內存當中進行&#xff0c;如下所示&#xff1a;這樣做有什么問題呢&#xff1f;注 意文末有&#xff1a;3625頁互聯網大廠面…

python--批量下載豆瓣圖片

溜達豆瓣的時候&#xff0c;發現一些圖片&#xff0c;懶得一個一個扒&#xff0c;之前寫過c#和python版本的圖片下載&#xff0c;因此拿之前的Python代碼來改了改&#xff0c;折騰出一個豆瓣版本&#xff0c;方便各位使用 # -*- coding:utf8 -*- import urllib2, urllib, socke…

linux touch權限不夠,Linux下的Access、Modify、Change , touch的使用以及權限問題

每個文件在linux下面都會記錄許多的時間參數&#xff0c;其實是有三個主要的變動時間&#xff0c;那么&#xff0c;這三個時間的意義又是什么&#xff1f;下面我們來介紹&#xff1a;* Modify time(mtime)當該文件的“內容數據”更改時&#xff0c;就會更新這個時間。內容數據指…

scala 獲取數組中元素_從Scala中的元素列表中獲取隨機元素

scala 獲取數組中元素We can access a random element from a list in Scala using the random variable. To use the random variable, we need to import the Random class. 我們可以使用隨機變量從Scala中的列表訪問隨機元素。 要使用隨機變量&#xff0c;我們需要導入Rand…

ubuntu14.04下安裝cudnn5.1.3,opencv3.0,編譯caffe及配置matlab和python接口過程記錄

已有條件: ubuntu14.04cuda7.5anaconda2(即python2.7)matlabR2014a 上述已經裝好了,開始搭建caffe環境. 1. 裝cudnn5.1.3,參照:2015.08.17 Ubuntu 14.04cuda 7.5caffe安裝配置 詳情:先下載好cudnn-7.5-linux-x64-v5.1-rc.tgz安裝包(貌似需要官網申請) 解壓: tar -zxvf cudnn-7.…

python excel導入oracle數據庫_【Python代替Excel】12:Python操作oracle數據庫

日常工作中&#xff0c;如果有數據庫權限&#xff0c;那么在oracle中提取數據、在Python中處理是比較方便的。Python也提供了一個庫專門操縱數據庫。今天就專門來講講如何在Python中操作數據庫。準備工作需要工具&#xff1a;oracle、PL/SQL、Pythonimport cx_Oracle如果用anac…

Linux 金字塔 的shell命令,linux下保留文件系統下剩余指定數目文件的shell腳本

原文出處&#xff1a;http://www.jbxue.com/article/13808.html (原創文章&#xff0c;轉載請注明出處)本節內容&#xff1a;保留文件系統下剩余指定數目的文件例子&#xff1a;#!/bin/bash#-------------------------------#Description: Back up your files#site: www.jbxue.…

前端干貨之JS最佳實踐

持續更新地址 https://wdd.js.org/js-best-pr... 1. 風格 一千個讀者有一千個哈姆雷特&#xff0c;每個人都有自己的code style。我也曾為了要不要加分號給同事鬧個臉紅脖子粗&#xff0c;實際上有必要嗎&#xff1f; 其實JavaScript已經有了比較流行的幾個風格 JavaScript Sta…

python requests和urllib_Python——深入理解urllib、urllib2及requests(requests不建議使用?)...

深入理解urllib、urllib2及requestsPython 是一種面向對象、解釋型計算機程序設計語言&#xff0c;由Guido vanRossum于1989年底發明&#xff0c;第一個公開發行版發行于1991年&#xff0c;Python 源代碼同樣遵循 GPL(GNU General PublicLicense)協議[1] 。Python語法簡潔而清晰…

ssh查找linux端口,linux – 查找當前連接的端口號SSH

我正在使用SSH連接創建一個本地模擬器(未連接到Internet).我已經開始使用特定范圍的端口號進行sshd,并對一系列設備進行NAT處理.我必須找到當前連接的端口號.OS CentOS 5.5OpenSSH 6.1我做了以下事情.它適用于正常使用(手動用戶).但是當嘗試嚴格的測試(自動化)時,似乎有時找不到…

this.getstate_Java線程類Thread.State getState()方法(帶示例)

this.getstate線程類Thread.State getState() (Thread Class Thread.State getState()) This method is available in package java.lang.Thread.getState(). 軟件包java.lang.Thread.getState()中提供了此方法。 This method is used to return the state of this thread. 此方…

Java資源大全中文版(Awesome最新版)

來源&#xff1a;http://www.cnblogs.com/best/p/5876559.html 目錄 業務流程管理套件字節碼操作集群管理代碼分析編譯器生成工具構建工具外部配置工具約束滿足問題求解程序持續集成CSV解析數據庫數據結構時間日期工具庫依賴注入開發流程增強工具分布式應用分布式數據庫發布文檔…