文件的原理和應用

常識:

1 文件包括屬性和內容

2 文件有打開和未打開文件,

3 本文先討論誰打開的文件,以及如何管理已經打開的文件

一 回憶c接口

1?fopen

??????? 我們在test.c里面用一下fopen函數,不存在打開的文件會默認創建,那為什么默認新建在當前目錄下是因為cwd,而不是PWD,我們知道PWD是環境變量,如果我們去到其它工作目錄,PWD會變,但是CWD不變,此時再運行一下test.c,此時文件還是會創建在CWD存的路徑下,而不隨著環境變量改變而變化。

2 fwrite

????????fwrite函數可以往文件寫數據,值得一提的是fwrite的size參數,這個是要寫入的字節數,我們大部分時候都是往文件寫個字符串,例如"hello linux",有時候size傳strlen("hello linux"),有時候傳sizeof(hello linux),我們會發現sizeof多寫入的\0被文件識別為亂碼,這說明一個問題,字符串結尾有\0這個字符是c語言的規定,文件是不認這個\0是字符的。

二?文件操作和系統調用

????????fwrite庫函數一定封裝了系統調用因為文件是在磁盤上的,fwirte要往硬件寫數據,那不就相當于訪問硬件的資源,由于操作系統不相信用戶,所以fwrite一定不是直接把數據弄給硬件,而是通過操作系統的接口將數據傳給硬件。接下里就來認識認識幾個系統調用。

????????1?認識open

??????? 從fopen的名字上看,我們也知道fopen封裝的是open,接下來就看看open的參數和返回值。man 2 open就可從手冊調出open的信息。

顯然,函數1是函數2的的子集合,我們只要說清楚了函數2,函數1的使用也就明白了。

參數1 文件名,不帶路徑應該是默認在當前路徑下找。

參數2 flags是什么呢?

????????

????????我們要給flags傳的是上面圖片中的宏,這些宏都表示一個一個的整數,接下來就介紹介紹這些宏的意義,以及如何使用O_RDONLY表示open以只讀方式打開,O_WRONLY表示open以寫方式打開, ?而O_RDWR則表示以讀寫方式打開,這三個宏最好只出現一個,至于其它的宏O_APPEND,這個是表示向文件寫時以追加的方式去寫。

使用:

| :按位或?這個使用又是啥意思呢??

????????舉個例子,O_RDONLY可能是用0001來表示,O_WRONLY則是0010O_RDWR則是0100來表示,同理得,O_APPEND就要用1000來表示,只用了一個比特位就能唯一表示一個宏,這樣的設計非常巧妙,首先我們可能會傳多個宏,設計者沒有用可模板參數來接收,而是只用一個整型,因為我們可以對傳的參數進行按位或,這樣只要對按位或的結果一分析,就知道你打開文件是要讀還是寫了,所以flag的類型就只是個樸素的int,可其實里面門道也不少。

參數3 權限初始化,因為我們open發現打開文件不存在,要創建文件,此時文件的權限是要指定的,不然會給一個初始值,但這個初始值如下圖。

? ? ? ?2?認識write和read

write和read就簡單多了。

write:往fd這個文件描述符對應的文件寫入buf數組中的元素,字節數為count。

read:從fd這個文件描述符對應的文件讀取count個字節的數據,寫入buf數組中。

????????現在我們就能解釋:現在我們就可以解釋為什么fwrite就傳一個"w"可以實現清空寫,以及創建文件,"w+"為什么能實現追加寫,就是因為在底層封裝了這些宏,然后操作系統識別到了,在調用系統調用的時候傳了給flag傳了不同的宏,至于返回值會在下面訪問文件的本質中提及。

三?訪問文件的本質

????????open的返回值-文件描述符,這個文件描述符怎么是int類型呢,我fopen用的可是FILE*,這兩者有什么關系嗎?

? ? ? ? 先來看看操作系統如何管理文件,首先操作系統打開的文件有很多,這些必然會被操作系統管理,操作系統管理文件,就像管理進程一樣,只要用一個file結構體描述文件即可,根本就不需要管文件內容,這樣在系統內核處,就又增加了一個數據結構將所有的file結構體管理起來誒,不對啊,文件不是進程打開的嗎,那不是應該進程管理嗎,如果僅僅是被進程管理,那如果進程出異常了,被kill了,這些文件不就丟失了?所以系統必須也要管理。如下圖:

? ? ? ? 好吧,既然上面是系統管理文件的方式,那進程呢怎么管理呢?

????????所以會有一個files_struct(這個和FILE*可不相同)來管理,這個結構體內部會有一個數組,數組每元素就是一個文件指針,而文件描述符就是數組下標,所以說一個文件描述符一定對應一個文件,當然多個文件描述符可以對應同一個文件(file結構體內部肯定是會有引用計數記錄的)也就是說底層進程是通過下標來找文件指針,從而找到文件的,所以FILE*內部一定封裝了文件描述符,不然系統調用找不到文件。

????????我們發現所有語言寫的代碼運行起來都要默認打開三個文件,stdin,stdout,stderror,因為系統就要這樣做,系統設計這就認為開機后天然需要鍵盤,顯示器文件,所以就要打開,而所有語言寫的代碼不管寫了啥,形成進程后,就會把已經打開的文件填到files_struct內,所以程序一運行,該數組內就有了三個元素。

????????既然stderror和stdout都是指向顯示器文件,它們的區別是什么,我想也就是其內部的封裝的文件描述符不同,當我們close(1),printf就用不了了,但是perror還可以向顯示器打印。

四?重定向

? ? ? ? 周邊小知識:write寫的時候如果不close,一直寫,那就會一直往后寫,而不是覆蓋,open以追加方式寫,指的是第一次write寫的時候從哪開始寫。

1 文件描述符的分配規則

? ? ? ? 自數組開頭遍歷,在數組中最先遇到的空格位置的下標,就是被分配的文件描述符。先前已經說了系統會打開兩個文件(說打開三個是方便理解),這兩個文件是鍵盤,顯示器,而顯示器被打開了兩次,在files_struct內的數組就會有三個文件描述符,其中0存的是鍵盤文件指針,1,2存的都是顯示器文件指針,我前面說多個文件描述符可以對應同一個文件,這就是實實在在的例子。

2?手動實現重定向

????????輸出重定向就是printf本來是要寫給顯示器的,但是由于close(1),然后又打開了myfile.txt后占用了一號位(這就驗證了文件描述符的分配規則)。

    1 #include<stdio.h>2 #include<stdlib.h>3 #include<unistd.h>4 #include<string.h>5 #include <sys/types.h>6 #include <sys/stat.h>7 #include <fcntl.h>8 int main()9 {10     printf("我的id:%d\n",getpid());11     close(1);
W> 12     int fd = open("myfile.txt", O_CREAT|O_WRONLY,0666);13     printf("我的id:%d\n",getpid());                                                14     return 0;15 }~

所以兩句printf就只有一句輸出,因為第二句printf就變成往myfile.txt輸出了。

????????這也側面說明在操作系統看來,往顯示器寫和普通的文件沒有區別,而printf內部用的stdout一定是封裝了1號文件描述符,這是編碼定死的,printf也不管這個標識符對應的文件變了沒,拿到就寫,就有了輸出重定向這種烏龍。

3 系統調用dup2

? ? ? ? 雖然可以先close,再打開文件實現重定向,但這樣的代碼還是不如直接調用系統調用那么優雅,直接上代碼,看看使用。結果一致。

問題1?oldfd和newfd誰覆蓋誰顯然從先前的例子來看,是oldfd上的內容覆蓋到newfd的內容,本質是數組對應下標上元素,也就是文件指針的拷貝。

讀者可以嘗試進行輸入重定向

同理也就是對0號位置下標做手腳

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

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

相關文章

【Kettle實戰】字符串處理及網絡請求JSON格式處理

經過大量的kettle操作實踐&#xff0c;我們會漸漸掌握一些技巧&#xff0c;大大減輕清洗的工作量。比如在哪里 處理字符串更方便&#xff0c;在哪兒處理更合理都是一個取舍問題。 字符串拼接 MySQL中使用concat(字段1,字段2)&#xff0c;但是如果“字段2”為NULL&#xff0c;結…

高速公路智能公專融合調度系統方案

在現代高速公路交通設施中&#xff0c;無線對講通信系統已經慢慢成為至關重要的環節。完善無線通信系統可以實現語音和數據的實時傳輸&#xff0c;確保調度中心和現場工作人員的及時溝通&#xff0c;快速響應和提供協調支持。隨著國內高速公路的發展&#xff0c;通信系統建設需…

11月22日,每日信息差

今天是2023年11月22日&#xff0c;以下是為您準備的15條信息差 第一、微軟將投資5億美元在魁北克擴大云計算和人工智能基礎設施 第二、奇安信預計與中國電子CEC業務量大幅增加 第三、極數云舟發布云舟數據編織系統“Ark Fabric” 第四、美國企業對特定電子眼鏡產品及其組件…

如何在windows使用別名遠程執行命令

需求背景 在開發中,需要在服務器執行腳本,需要如下幾步操作: 1.打開xshell 2.登錄服務器 3.進入命令腳本的路徑 4.執行腳本 但是,作為懶人來說,操作太繁瑣了,真麻煩,能不能一鍵就解決那么多操作?所以,開始研究windows有沒有這個東西,而且不需要額外的軟件就可以實現的.結…

ABeam Recruiting | ABeam旗下德碩管理咨詢(上海)最新招聘崗位

誠聘英才 市場部經理 招聘背景 作為起源于亞洲的全球化咨詢公司&#xff0c; ABeam立志成為中國、乃至全球的杰出品牌 本次招聘崗位 以加快ABeam中國本土各法人 在中國市場的品牌推廣、提高企業知名度 強化Marketing部門的體制為目標 工作職責 在現有的PR業務基礎上&#…

PyTorch離線安裝

文章目錄 python安裝1. Anaconda 下載2. Anaconda 安裝pytorch安裝3. 顯卡配置(無 Nvidia 顯卡的略過)4. 新建虛擬環境,用于存放pytorch5. 安裝 CUDA6 安裝pytorch(torch,torchvision,torchaudio)7. 驗證是否安裝成功python安裝 1. Anaconda 下載 在機器學習,深度學習中…

C++多線程學習(二):多線程通信和鎖

參考引用 C11 14 17 20 多線程從原理到線程池實戰代碼運行環境&#xff1a;Visual Studio 2019 1. 多線程狀態 1.1 線程狀態說明 初始化 (lnit)&#xff1a;該線程正在被創建就緒 (Ready)&#xff1a;該線程在就緒列表中&#xff0c;等待 CPU 調度運行 (Running)&#xff1a;…

xss-labs靶場6-10關

文章目錄 前言一、靶場6-10關1、關卡62、關卡73、關卡84、關卡95、關卡10 總結 前言 此文章只用于學習和反思鞏固xss攻擊知識&#xff0c;禁止用于做非法攻擊。注意靶場是可以練習的平臺&#xff0c;不能隨意去尚未授權的網站做滲透測試&#xff01;&#xff01;&#xff01; …

在win10上安裝pytorch-gpu版本2

安裝anaconda即下載了python&#xff0c;還可以創建虛擬環境。 目錄 1.1 anaconda安裝 1.2 pytorch-gpu安裝 1.1 Anaconda安裝 anaconda的安裝請看我之前發的tensoflow-gpu安裝&#xff0c;里面有詳細的安裝過程&#xff0c;這里不做重復描述&#xff0c;傳送門 1.2 pyt…

羊大師提示,羊奶都有哪些驚人功效?

羊奶不僅是一種美味的健康飲品&#xff0c;在近年來備受矚目的的健康圈子里&#xff0c;羊奶還被賦予了更多的功效&#xff0c;成為一種備受推崇的保健品。羊奶不但富含營養&#xff0c;而且還有著非常多的益處&#xff0c;它能夠用來美容、保健&#xff0c;甚至還可以治療某些…

【Java】多線程-單例模式/volatile-指令重排序

單例模式即代碼中只有一個實例的模式 適用場景&#xff1a;有些場景下&#xff0c;有的類只能有一個對象&#xff0c;不能有多個 要注意&#xff1a;在單例模式下&#xff0c;要保證不能產生多個實例 1、餓漢模式 class Singleton{private static Singleton instance new …

Mybatis plus 簡介

簡介 MyBatis-Plus (opens new window)&#xff08;簡稱 MP&#xff09;是一個 MyBatis (opens new window)的增強工具&#xff0c;在 MyBatis 的基礎上只做增強不做改變&#xff0c;為簡化開發、提高效率而生。 官網:https://baomidou.com/pages/24112f/ 特性 無侵入&…

英語常見的21組重點必背短語

短語: at at once 立刻&#xff0c;馬上 at least 至少 at most 最多 at last 最后 at home 在家 at noon 在中午 at night 在夜晚 at times 有時&#xff0c;偶爾 at school 在上學 at table 在吃飯 at present 目前&#xff0c;現在 at work 在工作 at all 全然&#xff0c…

《QT從基礎到進階·三十八》QWidget實現炫酷log日志打印界面

QWidget實現了log日志的打印功能&#xff0c;不僅可以在界面顯示&#xff0c;還可以生成打印日志。先來看下效果&#xff0c;源碼放在文章末尾&#xff1a; LogPlugin插件類管理log所有功能&#xff0c;它可以獲取Log界面并能打印正常信息&#xff0c;警告信息和錯誤信息&…

runnergo全棧測試平臺

一、全棧測試平臺runnergo使用 官網 官方使用文檔 二、單接口測試 三、性能測試 1.性能測試 2.性能測試報告 四、自動化測試&#xff08;暫時不支持UI自動化&#xff0c;或許會上&#xff09;

Jmeter 壓測實戰保姆級入門教程

1、Jmeter本地安裝 1.1、下載安裝 軟件下載地址&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/apache/jmeter/binaries/ 選擇一個壓縮包下載即可 然后解壓縮后進入bin目錄直接執行命令jmeter即可啟動 1.2 修改語言 默認是英文的&#xff0c;修改中文&#xff0c;點擊…

使用Java Servlet生成動態二維碼

文章目錄 引入ZXing庫創建QRCodeServlet部署到Servlet容器拓展功能1. 動態生成二維碼內容2. 調整二維碼尺寸3. 錯誤修正級別4. 日志輸出 結語 &#x1f389;歡迎來到Java學習路線專欄~探索Java中的靜態變量與實例變量 ☆* o(≧▽≦)o *☆嗨~我是IT陳寒&#x1f379;?博客主頁&…

【追求卓越04】數據結構--棧與隊列

引導 今天我們開始學習棧與隊列的內容&#xff0c;我覺得棧并不難&#xff0c;所以篇幅也就不會那么多了。在虛擬空間中&#xff0c;棧是用戶空間中的一種數據結構&#xff0c;它主要用于保存局部變量。那么問題來了&#xff0c;為什么用棧來保存局部變量&#xff0c;不用別的數…

Spring Boot 3 集成 Knife4j

基礎環境 SpringBoot : 3.0.6 Java: jdk-17.0.5 Maven: 3.6.1依賴 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xs…

Go 語言函數、參數和返回值詳解

函數是一組語句&#xff0c;可以在程序中重復使用。函數不會在頁面加載時自動執行。函數將通過調用函數來執行。 創建函數 要創建&#xff08;通常稱為聲明&#xff09;一個函數&#xff0c;請執行以下操作&#xff1a; 使用 func 關鍵字。指定函數的名稱&#xff0c;后跟括…