文件與fd

文件與fd

  • 一、前置預備
  • 二、復習c語言文件
  • 三、系統文件認識
    • 3.1 系統層面有關文件的接口(open):![在這里插入圖片描述](https://i-blog.csdnimg.cn/direct/b15577967d1445b08cd5252f2009683a.png)
    • 3.2 簡單使用open參數
    • 3.3 語言vs系統
    • 3.4 進一步理解文件描述符:
  • 四、內核中的文件
    • 4.1 初步了解
    • 4.2 理解一切皆文件:
    • 4.3 IO基本過程
    • 4.4 重定向

一、前置預備

在這里插入圖片描述

1、首先我們先回憶一下,在linux的前幾章,文件=內容+屬性(時間等屬性)
2、在c語言中使用文件的形式是固定的—先打開文件,然后操作文件,最后關閉文件,那為什么在訪問文件之前我們必須先打開它了?
(1)首先我們需要知道文件沒有被打開時存放在哪里?----一般來說文件都存放于磁盤
(2)那是誰在訪問文件?----是不是當前我們寫的代碼所編譯形成的程序啊,這個程序我們也可以稱為一個進程
(3)既然是進程來訪問我們的文件,那根據我們前面所學的知識,進程是不是需要被加載到內存中然后被cpu來執行,當進程運行到打開文件這一行代碼時,cpu能夠直接去讀取磁盤上的文件嗎?—很顯然是不能的(馮洛伊曼),所以打開文件本質上就是文件加載到內存當中,那我們可以類比一下,進程被加載到內存時,進程=內核數據結構+代碼、數據,文件是不是可以認為,文件=內核數據結構+文件內容
3、結論:我們研究打開的文件,是在研究:進程和文件的關系
4、研究文件系統可以分為兩部分來學習:
(1)沒有被打開的文件(磁盤)
(2)被打開的文件(內存)

二、復習c語言文件

1、在c語言或者c++中,一個進程會默認打開3個文件,就是標準輸入輸出流和錯誤流,對應的就是鍵盤、顯示器。但是我們知道鍵盤和顯示器都是硬件設備,我們能夠直接通過程序訪問硬件設備嗎?—很顯然不能,原因后面講解。(stdin / stdout / stderr)
2、是誰默認打開這三個標準輸入輸出流?----進程

下面就是c語言中對文件的兩種操作方式:
在這里插入圖片描述

1、w(只寫),Truncate file to zero lengh or create text file for writing.(>)
(1)沒有該文件,創建該文件,并且寫入
(2)有該文件,但是沒有對文件寫入,則清空
(3)有該文件,并且有寫入,從0位置覆蓋式寫入
在這里插入圖片描述

2、a(追加),顧名思義不會清空該文件內容,而是從結尾繼續添加寫入的內容(>>)
在這里插入圖片描述

3、我們有幾種打印到屏幕的方式?:(純C)
在這里插入圖片描述
4、我們知道用戶是不能直接訪問硬件的(磁盤,顯示器,鍵盤),要想訪問必須經過OS,所以我們所使用的C文件接口,底層一定封裝了對應的文件類系統調用

三、系統文件認識

在c語言或者c++中,文件的操作其實是給我們封裝好的,我們調用語言內的函數,然后它又調用系統接口,那我們現在就來看一下系統中文件的接口

3.1 系統層面有關文件的接口(open):在這里插入圖片描述

open中的參數:
(1)pathname:文件的文件名
(2)flags:常見的打開方式
O_RDONLY(只讀)、 O_WRONLY(只寫)、O_RDWR(讀寫),O_TRUNC(存在該文件就清空)、
O_CREAT(創建)、O_APPEND(若文件操作,追加),這些打開方式本質上是宏
第二個位置的操作方式可以傳多個,但是一般來說系統的接口是c語言的,不支持可變參數,這里是通過位圖的方式實現的,下面我們通過簡單的代碼來看下位圖是如何控制標記位的
在這里插入圖片描述
(3)mode:權限位,在系統中文件管理與權限管理是兩個不同的模塊,如果文件已經存在,第三個參數沒有影響,但是如果我們是打開一個新的文件時,會創建一個新的文件,如果不帶第三個參數,那么該文件的權限是亂碼。
(4)系統中的open調用是有返回值的,它的返回值類型為int,當文件操作失敗返回-1,正常操作返回 !0,我們一般稱這個返回值叫做文件描述符。

在這里插入圖片描述
由上圖我們可以看到,本質上系統中文件調用的接口只有兩個,兩個接口差別很微小,只有第三個參數的差別。(如果文件不存在,我們建議使用三參數open,如果文件已經存在則建議使用兩參數open)

3.2 簡單使用open參數

1、打開文件:
在這里插入圖片描述
這里的umask不會改變系統的umask

2、touch的簡單實現:
在這里插入圖片描述

3、關閉文件(close),讀(read),寫(write),
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

綜合使用文件接口:
在這里插入圖片描述

3.3 語言vs系統

在這里插入圖片描述
總結:語言上的fopen就是封裝的系統調用接口

3.4 進一步理解文件描述符:

在這里插入圖片描述

1、文件描述符我們可以簡單的理解為該文件在當前程序操作的所有文件中的序號,一般來說我們打開的文件默認從3開始,因為系統默認打開了三個文件,stdin(0),stdout(1),stderr(2)。
在這里插入圖片描述

2、字符串以\0結尾是c語言的規定,跟文件無關,所以寫文件時只寫字符長度,如果寫的時候讓長度+1,也就是想將\0也寫入,這個時候系統會默認\0為亂碼

四、內核中的文件

4.1 初步了解

上面我們簡單的介紹了系統中的文件調用,現在我們來理解一下內核中的文件:
在這里插入圖片描述
1、在文件沒有啟動時它是以內容+屬性的形式存儲于磁盤空間內部
2、文件被打開是進程(task_struct)來打開的,也就是文件加載到內存中(創建struct file)
3、進程被CPU調度時會調用open系統調用
4、在內存中存在很多個struct file的結構體對象,它管理著文件的打開屬性,系統默認會打開3個文件(鍵盤,顯示器,顯示器),在OS層面上,有一個file list將所有結構體鏈接起來,對文件的管理,變成了對鏈表的增刪查改
5、進程也是由一個鏈表鏈接起來管理的(task_struct)
6、進程鏈表管理進程,file鏈表管理文件,OS層面是解耦合的,(一個進程-----多個文件)為了讓兩者相關聯,PCB內部存在一個指針(struct files_struct* files),OS會為每個進程里的該指針創建一個struct files_struct的結構體,其中會存在一個叫做struct file* fd_array[N]的數組(指針數組)
7、上面這個數組中下標對應的位置直接連接文件的結構體
8、文件描述符本質上是數組下標,進程和文件用指針來相關聯
9、OS層面,fd是唯一訪問文件的方式,FILE是C提供的訪問文件的結構體,它會有很多的屬性 --(其中有一個屬性必定對fd做封裝)
在這里插入圖片描述
在這里插入圖片描述

4.2 理解一切皆文件:

在這里插入圖片描述
1、之前我們說過每一個硬件都有一個共同的名字叫做外設,我們如果整體來看的話可以發現所有設備可以擁有相同的屬性類別,但是屬性具體的值可以不一樣,怎么理解呢?例如:設備號,狀態值等,所以我們是可以將所有的外設用一個結構體去描述的,現在我們要訪問鍵盤、網卡、磁盤以及顯示器,對上述設備的訪問的方式一定是不同的,例如鍵盤只能讀,顯示器只能寫,那這個結構體怎么才能將所有設備統一呢?

2、在外設的角度上,所有的設備都其實實現了read和write方法,但上面我們剛說有些外設只需要其中一種,這個不必擔心,需要的方法我們不去實現它即可

3、站在linux操作系統上,對一個文件進行操作之前,我們都會創建一個struct file,這個結構體里會有一系列的調用外設的方法,我們來介紹其中最典型的兩個,就是
int (*read) ();
int (*write) ();

操作系統通過函數指針的形式來訪問外設的操作函數,如此現在我們就不需要關心鍵盤、網卡、顯示器、、、的具體函數實現,我們只需要調用接口即可,這一套機制我們稱為vfs(虛擬文件系統)

4、在struct file中又會提供文件描述符,所以我們對文件的操作轉化到了對文件描述符上的操作,系統調用也是通過對這些函數指針操作的

5、上面介紹的這種上層的struct file與外設的struct device這種技術實際上就是多態的實現原理
在這里插入圖片描述文本寫入 vs 二進制寫入
在這里插入圖片描述
1、我們需要明白顯示器顯示12345,這里到底是一個整數還是5個數字字符?–其實這里顯示器顯示的是5個字符,所以實際上我們編寫的代碼中輸出所有整數類型,系統都會先轉化為字符,然后再在顯示器打印,系統就覺得太麻煩了,每次都需要我們自己轉換,并且我們寫的可能還會出現許多問題,故此系統封裝了一系列函數

2、c語言中的scanf與printf它叫做格式化輸入與輸出,它的作用就是將文件內的內容以固定格式來輸入輸出,其次計算機所謂的文本與二進制其實沒有本質差別,不管我們輸入的是字符,數字,符號,本質上計算機都是以二進制處理的,例如可執行文件,我們要知道可執行文件會被編譯成二進制,我們向二進制文件輸入文件,它會認識嗎?

3、那為什么c、c++還會封裝一系列函數呢?這是因為雖然系統給我們做了一層封裝,但是要是換系統了呢?上面我們都是基于linux系統來談的,封裝的好處就是語言的可移植性

4、為什么我們使用c語言的庫函數在linux或者win下都可以隨便使用?這是因為這些庫函數的代碼其實全部都封裝在庫內(glic)當我們需要調用庫內的函數時,系統會將該函數編譯成當前系統的版本,例如win版,linux版。所以在使用一門語言時,需要先安裝環境,安裝環境就是安裝庫
在這里插入圖片描述

4.3 IO基本過程

1、input:當我們調用write函數時,我們通過文件描述符找到了文件操作表,又在文件操作表中通過函數指針調用寫的操作,但我們寫的內容并不是直接就寫入硬盤的,而是先寫入文件內核緩沖區,再刷新至硬盤文件空間,刷新是由os自主決定,意識是指緩沖區有多少內容或者多少時間執行一次刷新,由操作系統來決定
2、output:與上面的操作相反,但也是現將硬盤上的文件內容拷貝至緩沖區,然后os自主決定刷新

緩沖區(系統)的存在是因為內存的操作速度太快了,外設的操作速度非常的慢(例如我們要進行IO操作,如果沒有緩沖區,我們每進行一個字符的操作就都要進行一次外設的訪問,效率太低了,但現在我們有了緩沖區,也就是說我們現在可以向緩沖區寫入100或者1000的數據然后進行一次寫入寫出,效率大大的提升了),同時系統也會進行預加載,進一步提升IO地效率
所以write與read本質上是拷貝函數。

在這里插入圖片描述

4.4 重定向

1、fd的分配規則:進程打開文件,需要給文件分配新的fd(最小的,沒有被使用的),如果系統默認的0,1,2被關閉,系統也會將0,1,2分配出去

在這里插入圖片描述
1、在上面的代碼中如果沒有關閉1,這個文件的話,會默認打印3,4,5,6在顯示器上,這也符合我們的預期,但當我們關閉1后,本來應該向顯示器打印的內容,卻寫入到了log1.txt文件中,這是為什么呢?
這是因為printf函數默認會向stdout這個文件打印,我們知道printf也是通過文件描述符去操作文件的,但是printf只認1這個文件描述符,但此時1這個文件描述符已經被log1.txt給占用了,所以現在的操作變為了向log1.txt寫入了

所謂的重定向就是系統只認0,1,2,但是現在我們讓特定文件描述符內的內容做出修改,而系統毫不知情
系統的中重定向接口叫做dup2

在這里插入圖片描述
系統實現重定向的方式非常簡單,0,1,2這三個位置本質上是指針數組,我們現在讓數組內3號位置的指針,拷貝到1號位置,這就是輸出重定向,這一些列操作都必須使用系統調用也就是dup2(oldfd,newfd)
例如輸出重定向就是dup2 (fd,1);
在這里插入圖片描述
在這里插入圖片描述

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

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

相關文章

語義通信高斯信道仿真代碼

1?? 代碼 def AWGN(coding, snr, devicecpu):"""為輸入張量添加高斯白噪聲(AWGN),根據指定的 SNR(分貝)控制噪聲強度。參數:coding (torch.Tensor): 輸入張量,形狀為 [batch_s…

unity中實現機械臂自主運動

目的:導入機械臂的fbx模型,利用C#編寫腳本實現機械臂的自主運動步驟1.在 Unity 中,右鍵點擊 “Assets” 文件夾,選擇 “Create” -> “C# Script” 來創建一個新的 C# 腳本命名為 “ArmController”。2.雙擊打開腳本&#xff0…

Python 版本與 package 版本兼容性檢查方法

網羅開發(小紅書、快手、視頻號同名)大家好,我是 展菲,目前在上市企業從事人工智能項目研發管理工作,平時熱衷于分享各種編程領域的軟硬技能知識以及前沿技術,包括iOS、前端、Harmony OS、Java、Python等方…

深入剖析分布式事務的Java實現:從理論到Seata實戰

文章目錄深入剖析分布式事務的Java實現:從理論到Seata實戰引言:分布式事務的現實挑戰1. 分布式事務理論基礎1.1 從ACID到CAP/BASE1.2 典型業務場景分析2. 主流分布式事務解決方案對比2.1 技術方案全景圖2.2 選型建議3. Seata框架深度解析3.1 Seata架構設…

自建知識庫,向量數據庫 (十一)之 量化對比余弦——仙盟創夢IDE

向量比對:開啟企業經營自動化搜索新視野在當今數字化時代,企業經營自動化已成為提升競爭力的關鍵。其中,搜索功能作為企業獲取信息、連接用戶與資源的重要入口,其效率和準確性直接影響企業的運營效率和用戶體驗。向量比對在企業經…

Spring Cloud系列—SkyWalking告警和飛書接入

上篇文章: Spring Cloud系列—SkyWalking鏈路追蹤https://blog.csdn.net/sniper_fandc/article/details/149948321?fromshareblogdetail&sharetypeblogdetail&sharerId149948321&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 目…

【問題】解決docker的方式安裝n8n,找不到docker.n8n.io/n8nio/n8n:latest鏡像的問題

問題概覽 用docker方式安裝n8n,遇到錯誤,安裝不了的問題: Unable to find image docker.n8n.io/n8nio/n8n:latest locally docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request can…

機器人控制基礎:串級PID控制算法的參數如何整定?

目錄 一、整定前的準備 二、內環(副環)參數整定(核心步驟) 1. 斷開主環,單獨測試內環 2. 內環參數整定(按 “比例→積分→微分” 順序) (1)比例系數(kp)整定 (2)積分系數(ki)整定 (3)微分系數(kd)整定(可選) 3. 驗證內環抗擾動能力 三、外環(主…

HTTP性能優化實戰指南(含代碼/圖表/案例)

HTTP性能優化實戰指南(含代碼/圖表/案例)一、性能優化關鍵指標TTFB(Time To First Byte): 服務器響應時間FCP(First Contentful Paint): 首內容渲染時間LCP(Largest Contentful Paint&#xff0…

QT代碼框架小案例:一個簡單的時間類(Time)及其實例化程序,模擬了時間的設置、顯示和自動流逝功能,類似一個簡易電子時鐘。

一、代碼框架二、運行終端顯示三、代碼詳細注釋test.pro# 指定項目類型為應用程序(而非庫或其他類型) TEMPLATE app# 配置項目:啟用控制臺輸出,使用C11標準 CONFIG console c11# 移除配置:不生成應用程序捆綁包&…

Nacos-11--Nacos熱更新的原理

在Nacos中,當監聽到配置變化后,Nacos提供了相關機制(長輪詢或gRPC)讓客戶端能夠監聽到配置的變化,并觸發相應的監聽器(Listener),但具體的處理邏輯需要根據實際需求來實現。 1、熱更…

fastapi 的BackgroundTasks

什么是 BackgroundTasks?BackgroundTasks 是 FastAPI 提供的一個強大工具,它允許你將一些非緊急的、耗時的操作(例如發送郵件、處理數據、調用第三方 API 等)放到“后臺”去執行,而不是讓用戶一直等待這些操作完成。它…

Python 十進制轉二進制

在 Python 中,將十進制整數轉換為二進制有多種方法。以下是幾種常見的方式:1. 使用 bin() 函數bin() 是 Python 內置函數,可以將十進制整數轉換為二進制字符串。語法bin(n)示例n 13 binary_str bin(n) print(binary_str) # 輸出: 0b1101說…

合并工作表,忽略手動隱藏行超簡單-Excel易用寶

同事小麗有一個工作簿,文件中有多個工作表,每個工作表中有多行數據,這些表格中數據是有手動隱藏行的,她想把這些表格的數據忽略隱藏行合并到一個工作表中,但是使勁渾身解數,各種折騰,都會把隱藏…

我從零開始學習C語言(14)- 基本類型 PART1

今天學習第7章-基本類型,主要內容如下:7.1 整數類型這里的整數的整數值就是數學意義上的整數。C語言支持兩種本質上(存儲形式)不同的數值類型:整數類型(簡稱整型)和浮點類型(簡稱浮點…

Flutter - UI布局

一、容器Widget1. ScaffoldScaffold 作為頁面的腳手架,基礎區域包含頂部導航欄 appBar、主體內容區 body、側邊抽屜 drawer、懸浮按鈕 floatingActionButton、底部導航欄 bottomNavigationBar。Scaffold(appBar: AppBar( // 頂部導航欄title: Text(首頁),),body: Ce…

UNIKGQA論文筆記

UNIKGQA: UNIFIED RETRIEVAL AND REASONING FOR SOLVING MULTI-HOP QUESTION ANSWERING OVER KNOWLEDGE GRAPH(ICLR 2023)Introduction知識圖上的多跳問題回答(KGQA)的目的是在大規模知識圖譜(KG)上找到自然語言問題中提到的主題實…

MySQL 8.0.17 “Too Many Connections” 排查指南

MySQL 8.0.17 “Too Many Connections” 排查與優化指南 在 MySQL 8.0.17 中,當出現“Too many connections”錯誤時,通常意味著數據庫連接數已達上限。這不僅會影響應用性能,還可能導致連接池(如 Druid)無法獲取新連接…

GEO優化服務:智能時代營銷新賽道的中國引領者——全球行業格局與發展趨勢觀察

隨著全球人工智能技術的迅猛發展,以GPT-5、Claude Opus以及我國的DeepSeek Divine、豆包等為代表的新一代生成式AI搜索引擎,正深刻改變著信息獲取與商業決策模式。用戶通過直接向AI提問獲取整合答案的行為日益普遍,傳統搜索引擎的流量入口地位…

全面解析主流AI模型:功能對比與應用推薦

全面解析主流AI模型:功能對比與應用推薦 在當前人工智能技術飛速發展的背景下,市面上涌現了多種具備不同能力的AI模型。本文將系統梳理主流模型的特性、對比其核心能力,并結合實際場景推薦高效、穩定的API服務(如https://api.aaa…