【Linux】基礎IO流

? 好的代碼自己會說話,清晰的邏輯與優雅的結構,是程序員與世界對話的方式。

前言

??這是我自己學習Linux系統編程的第五篇筆記。后期我會繼續把Linux系統編程筆記開源至博客上。?

? 上一期筆記是關于進程

【Linux】進程-CSDN博客https://blog.csdn.net/hsy1603914691/article/details/147628805

文件

文件的概念

1. 文件存儲在 磁盤中,而 磁盤是一種 永久性存儲介質,因此文件在磁盤上的保存具有持久性, 斷電后數據也不會丟失
2. 磁盤屬于 外部設備,既可用于 數據輸入,也可用于 數據輸出,因此對磁盤文件的所有操作,如讀取和寫入, 本質上都是對外設的數據傳輸,統稱為 IO操作

文件的性質

1. 即使是0KB的空文件也會占用磁盤空間。因為文件不僅包含實際的 文件數據,還包含 文件屬性
2. 換句話說,文件的本質是 "文件數據+ 文件屬性"。因此,所有的 文件操作,本質上都是對 文件內容的操作,或是對 文件屬性的操作。
3. 對文件的操作,本質上是 進程在操作系統層面對文件進行訪問。磁盤由操作系統進行統一管理,因此所有對文件的讀寫操作, 并不是直接由C/C++的標準庫函數完成的,這些庫函數只是為用戶提供了更便捷的接口。實際上,文件的讀寫操作最終是通過操作系統提供的 文件相關系統調用接口來實現的。

讀寫文件庫函數

FILE* fopen(char* path,char* mode);
fclose(FILE* fp);
fwrite(void* content, size_t size, size_t num, FILE*?fp);
fread(void* content, size_t size, size_t num, FILE*?fp);
fprintf(FILE* fp,char* format, ...)

1. 使用"w"模式打開文件時,文件內容會被清空然后從頭開始寫入新數據,這在功能上等價于Linux中的重定向操作符">"

2. 使用"a"模式打開文件時,數據會被追加到文件末尾原有內容不會被清空,這與Linux中的追加重定向操作符">>"的行為一致。

3.?fopenfclosefreadfwrite等函數屬于C標準庫的一部分,我們稱之為庫函數。4.?openclosereadwrite等則是操作系統提供的接口,稱為系統調用接口

5. 可以認為,C標準庫中的f系列函數本質上是對底層系統調用的封裝,目的是提供更友好、便攜的接口,方便開發者進行二次開發和跨平臺使用。

文件描述符?

1. 文件描述符(fd)本質上是一個整數。在C語言中,它被封裝在FILE結構體中以便于操作。其中,標準輸入(stdin)對應的文件描述符是0標準輸出(stdout)對應1標準錯誤(stderr)對應2

2. 對文件進行任何操作之前,必須先將文件加載到內核中對應的文件緩沖區中

3.?文件描述符的分配遵循以下規則:在file_struct數組中,找到當前未被使用的最小的一個下標,并將其作為新的文件描述符。

重定向原理?

1. 實現輸出重定向的關鍵在于:將文件描述符fd所指向的文件表項復制到下標為1(stdout)的位置。這樣一來,原本向1寫入的數據就會被寫入到fd所指向的文件中。這種操作通常通過系統調用dup2(fd,1)來實現。

2. 追加輸出重定向的實現方式與普通輸出重定向相同,不同之處在于打開文件時使用了 O_APPEND標志。這樣在寫入數據時,每次寫入的內容都會自動追加到文件末尾,而不會覆蓋已有內容。

3.?實現輸入重定向的關鍵在于:將文件描述符fd所指向的文件表項復制到下標為0(stdin)的位置。這樣一來,原本從0讀取輸入的操作就會從fd所指向的文件中讀取數據。這種操作通常通過系統調用dup2(fd,0)來實現。

#include <stdio.h>          
#include <sys/types.h>      
#include <sys/stat.h>       
#include <stdlib.h>        
#include <fcntl.h>         int main()
{close(1);             int fd = open("log.txt", O_WRONLY | O_CREAT, 00644);                     printf("fd--->%d\n", fd); return 0;
}

緩沖區

兩個緩沖區?

1.?緩沖區是內存中預留的一塊存儲空間,用于暫存輸入或輸出的數據。根據其對應的是輸入設備還是輸出設備,緩沖區可分為輸入緩沖區輸出緩沖區。?

2.?在讀寫文件時,如果沒有緩沖區,則每次操作都需要通過系統調用直接訪問磁盤,這會導致CPU頻繁切換狀態并降低效率。采用緩沖機制可以一次性加載大量數據到緩沖區,減少磁盤訪問次數,加快數據處理速度。

3. 使用stdio.h庫進行輸入輸出操作時,數據首先進入語言層面的緩沖區,并僅在用戶強制刷新進程正常退出時,才會將這些數據從緩沖區寫入文件的內核緩沖區

4.?在使用C語言庫函數進行輸入輸出操作時:

  • 寫入文件一般采用全緩沖機制,數據會在緩沖區填滿或手動刷新時寫入文件。
  • 寫入到顯示器則通常采用行緩沖機制,數據會在遇到換行符或緩沖區滿時自動刷新到屏幕。
全緩沖區寫滿再刷新
行緩沖區寫滿再刷新,遇到換行就刷新
無緩沖區沒用緩沖區
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{close(1); int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666); printf("hello world!\n"); fflush(stdout);close(fd);return 0;
}

模擬封裝libc庫

<mylibc.h>

#include <stdio.h>#define SIZE 1024
#define FLUSH_NONE 0
#define FLUSH_LINE 1
#define FLUSH_FULL 2struct IO_FILE
{int flag;//打開方式int fileno;//文件描述符char buffer[SIZE];//用戶層語言緩沖區int bufferlen;//緩沖區有效字符個數int flush_method;
};
typedef struct IO_FILE myfile;myfile* myfopen(const char* filename,const char* mode);
int myfwrite(const char* ptr,size_t len,myfile* stream);
void myfflush(myfile* stream);
void myclose(myfile* stream);

<mylibc.c>?

#include "mylibc.h"
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>myfile* myfopen(const char* filename,const char* mode)
{int fd=0,flag=0;if(strcmp(mode,"r")==0){flag=O_RDONLY;fd=open(filename,O_RDONLY);}else if(strcmp(mode,"w")==0){flag=O_CREAT|O_WRONLY|O_TRUNC;fd=open(filename,O_CREAT|O_WRONLY|O_TRUNC, 0666);}else if(strcmp(mode,"a")==0){flag=O_CREAT|O_WRONLY|O_APPEND;fd=open(filename,O_CREAT|O_WRONLY|O_APPEND, 0666);}myfile* my=(myfile*)malloc(sizeof(myfile));my->fileno=fd;my->flag=flag;my->bufferlen=0;my->flush_method=FLUSH_LINE;memset(my->buffer,0,sizeof(SIZE));return my;
}int myfwrite(const char* ptr,size_t len,myfile* stream)
{memcpy(stream->buffer+stream->bufferlen,ptr,len);stream->bufferlen+=len;if(stream->flush_method==FLUSH_LINE && stream->buffer[stream->bufferlen-1]=='\n')myfflush(stream);return len;
}void myfflush(myfile* stream)
{if(stream->bufferlen > 0){write(stream->fileno,stream->buffer,stream->bufferlen);fsync(stream->fileno);}stream->bufferlen=0;
}void myclose(myfile* stream)
{myfflush(stream);close(stream->fileno);free(stream);
}

<mytest.c>??

#include "mylibc.c"int main()
{myfile* my=myfopen("log.txt","a");char* msg="hello world!\n";myfwrite(msg,strlen(msg),my);myclose(my);return 0;
}

磁盤

LBA地址和CHS地址

1. LBA地址:是一種通過線性編號直接訪問硬盤上數據塊的方法,簡化了大容量存儲設備的管理和訪問。

2. CHS地址:是一種基于硬盤物理結構,使用柱面、磁頭和扇區三個參數來精確定位數據位置的傳統尋址方式。

3.?磁盤CHS定址過程:若要向磁盤寫入數據,首先需要移動磁頭至對應柱面然后等待盤片旋轉使磁頭對準目標扇區的起始位置,方可進行數據的讀取或寫入操作。

磁盤劃分

1.?一塊磁盤可以被劃分為多個"分區"。從Windows的角度來看,會將一塊磁盤劃分為C盤、D盤、E盤等,這些盤符對應的就是不同的分區。

2. 磁盤的每個分區被劃分為多個"塊"。其大小在格式化時確定且不可更改,最常見的大小為4KB,即由連續的八個512字節的扇區組成一個""

3.?磁盤作為典型的塊設備,其數據讀取方式并非以扇區為單位逐個進行,而是由操作系統按塊批量讀取,以此提升I/O效率和整體性能。

文件系統?

ext2文件系統

1. 在 ext2文件系統中,根據分區大小會被劃分為 若干個塊組(Block Group) 每個塊組都具有相同的結構組成。
2.? Inode和數據塊跨組但不跨分區 。因此在同一個分區內部, Inode和數據塊都是唯一的
3.? 每個塊組的開頭都有一份超級塊的副本,但只有第一個塊組的超級塊是必須存在的,其他塊組可以沒有。這是為了防止單個扇區損壞導致整個文件系統無法使用。
4. 分區完成后的 格式化操作,是對該分區進行分組,并在每個塊組中寫入超級塊、塊組描述符表、塊位圖、Inode 位圖等管理信息。

1.?Data Block:用于存放文件的實際內容,由一個個數據塊組成。

2.?Inode Table用于存儲文件的屬性信息,包括文件大小、所有者、權限、時間戳等屬性。

3. Block Bitmap :用于追蹤數據塊的使用狀態,它記錄了哪些數據塊已被占用,以及哪些數據塊仍處于空閑狀態。
4. Inode Bitmap :用于指示每個Inode的分配狀態,其中每一位表示一個Inode是否空閑可用。
5. GDT 用于記錄每個塊組的屬性信息。當一個分區被劃分為多個塊組時,每個塊組都會對應一個塊組描述符,每個塊組描述符包含了該塊組的數據信息:
  • Inode表的起始位置。
  • 數據塊區的起始位置。
  • 當前塊組中剩余的空閑Inode數量。
  • 當前塊組中剩余的空閑數據塊數量。
6. super block :用于存儲文件系統的整體結構信息,描述該分區上文件系統的核心屬性信息。 由于超級塊保存著整個文件系統的關鍵結構信息,一旦其內容被損壞,將可能導致整個文件系統無法識別或訪問,甚至造成數據丟失。 它記錄了包括以下內容在內的關鍵信息:
  • 數據塊和Inode的總數及當前未使用的數量。
  • 每個Block和Inode的大小。
  • 最近一次掛載的時間。
  • 最近一次寫入數據的時間。
  • 其他與文件系統相關的配置和狀態信息。

inode和datablock映射?

1. 由于每個分區擁有獨立的Inode和數據塊,所以只需知道Inode編號,就能在分區內確定其所在的組號和具體位置。然后,通過Inode中記錄的映射關系,可以找到存儲文件數據的具體數據塊。

2.?目錄本質上也是一種文件,但在磁盤上并不存在“目錄”這一特定概念,只有文件屬性和文件內容的區分。目錄的屬性與其他文件類似,其內容保存的是該目錄中的文件名與Inode號之間的映射關系。

3. 因此,訪問一個文件時,必須能夠打開當前所在目錄。具體來說,就是需要打開該目錄對應的目錄文件,根據其中保存的文件名與 Inode 號的映射關系,找到目標文件的 Inode,進而完成文件的訪問。

軟硬鏈接

軟鏈接

ln -s xxx yyy創建一個指向文件xxx的軟鏈接yyy

1. 軟鏈接是一種特殊的文件類型,它作為一個獨立的實體存在,擁有自己獨立的inode編號。

2. 軟鏈接的內容實際上是其所指向的目標文件或目錄的路徑。這意味著當你訪問軟鏈接時,系統會自動重定向到該鏈接所指向的實際文件或目錄。

硬鏈接?

ln xxx yyy創建一個文件xxx的硬鏈接yyy

1. 硬鏈接是指向同一個inode的另一個文件名。這意味著多個文件都指向存儲在磁盤上的同一份實際數據。

2. 硬鏈接具有以下性質:

  • 共享數據:xxxyyy共享相同的inode編號和數據塊。對任一名稱所做的更改都會反映在另一名稱上,因為它們實際上指向的是相同的數據。
  • 獨立性:雖然xxxyyy共享數據,但它們是彼此獨立的文件名。刪除其中一個文件名不會影響另一個文件名及其指向的數據,除非所有指向該inode的文件名都被刪除,這時數據才會真正被釋放。
  • 限制:硬鏈接只能在同一文件系統內創建,并且不能用于目錄(不允許用戶自己建)。

致謝

??感謝您花時間閱讀這篇文章!如果您對本文有任何疑問、建議或是想要分享您的看法,請不要猶豫,在評論區留下您的寶貴意見。每一次互動都是我前進的動力,您的支持是我最大的鼓勵。期待與您的交流,讓我們共同成長,探索技術世界的無限可能!

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

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

相關文章

【C語言】學習過程教訓與經驗雜談:思想準備、知識回顧(二)

&#x1f525;個人主頁&#xff1a;艾莉絲努力練劍 ?專欄傳送門&#xff1a;《C語言》、《數據結構與算法》、C語言刷題12天IO強訓、LeetCode代碼強化刷題 &#x1f349;學習方向&#xff1a;C/C方向 ??人生格言&#xff1a;為天地立心&#xff0c;為生民立命&#xff0c;為…

AD8021ARZ-REEL7【ADI】300MHz低噪聲運放放大器,高頻信號處理的性價比之選!

AD8021ARZ-REEL7&#xff08;ADI&#xff09;產品解析與推廣文案 1. 產品概述 AD8021ARZ-REEL7 是 Analog Devices Inc.&#xff08;ADI&#xff09; 推出的一款 高速、低噪聲運算放大器&#xff08;Op-Amp&#xff09;&#xff0c;屬于 ADI的高性能放大器系列&#xff0c;專為…

WPF學習筆記(11)數據模板DataTemplate與數據模板選擇器DataTemplateSelector

數據模板DataTemplate與數據模板選擇器DataTemplateSelector 一、DataTemplate1. DataTemplate概述2. DataTemplate詳解 二、DataTemplateSelector1. DataTemplateSelector概述2. DataTemplateSelector詳解 總結 一、DataTemplate 1. DataTemplate概述 DataTemplate 表示數據…

【V6.0 - 聽覺篇】當AI學會“聽”:用聲音特征捕捉視頻的“情緒爽點”

系列回顧&#xff1a; 在上一篇 《AI的“火眼金睛”&#xff1a;用OpenCV和SHAP洞察“第一眼緣”》 中&#xff0c;我們成功地讓AI擁有了視覺&#xff0c;它已經能像一個嚴苛的“質檢員”一樣&#xff0c;評判我視頻的畫質和動態感。 但我的焦慮并沒有完全消除。因為我發現&a…

(5)pytest-yield操作

1. 簡介 上一篇中&#xff0c;我們剛剛實現了在每個用例之前執行初始化操作&#xff0c;那么用例執行完之后如需要清除數據&#xff08;或還原&#xff09;操作&#xff0c;可以使用 yield 來實現。fixture通過scope參數控制setup級別&#xff0c;既然有setup作為用例之前前的操…

C++中的cmath庫

在C編程中&#xff0c;數值計算是科學計算、工程應用及算法開發的基礎。cmath庫作為C標準庫的重要組成部分&#xff0c;提供了豐富的數學函數和工具&#xff0c;能夠高效處理各種數值計算任務。本文將全面解析cmath庫的核心功能&#xff0c;并通過實戰案例展示其強大威力。 一…

python包管理工具uv VS pip

在 Python 中&#xff0c;uv 和 pip 都是包管理工具&#xff0c;但它們的定位和特性有所不同。以下是主要區別&#xff1a; 1. pip&#xff08;傳統工具&#xff09; 定位&#xff1a;Python 官方的包安裝工具&#xff0c;是 Python 生態中最基礎的包管理器。特點&#xff1a;…

OpenCv基礎(C++)

1.圖像讀取與顯示 #include<opencv2/opencv.hpp> using namespace cv;Mat src imread("C:/Users/16385/Desktop/new/photo/1.jpg");//讀取圖像 Mat src imread("C:/Users/16385/Desktop/new/photo/1.jpg",IMREAD_GRAYSCALE); //將讀取的圖像轉為灰…

MySQL非阻塞創建索引的方法

文章目錄 1. Online DDL (MySQL 5.6)2. pt-online-schema-change 工具3. gh-ost 工具4. 對于MySQL 8.0注意事項 在MySQL中創建大型表索引時&#xff0c;傳統方式會阻塞表的寫操作&#xff0c;影響生產環境使用。以下是幾種非阻塞創建索引的方法&#xff1a; 1. Online DDL (My…

數字雨動畫背景

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>數字雨動畫背景</title><style>* {m…

分布式鎖的概念與應用場景

一、分布式鎖的核心概念 分布式鎖是一種在分布式系統環境下&#xff0c;用于保證多個進程/節點對共享資源實現互斥訪問的機制。其本質是通過某種中間件&#xff08;如Redis、ZooKeeper等&#xff09;實現跨節點的鎖控制&#xff0c;確保在分布式環境中&#xff0c;同一時刻只有…

js代碼09

題目 好的&#xff0c;我們繼續。 在上一個練習中&#xff0c;我們深入探討了 this 的復雜性。你會發現&#xff0c;ES6 引入的 class 語法在很大程度上就是為了簡化 this 的使用&#xff0c;并為 JavaScript 提供一個更清晰、更熟悉的面向對象編程&#xff08;OOP&#xff0…

基于Airtest的App數據爬取實戰:突破傳統爬蟲的邊界

引言:App數據爬取的技術困境 在當今移動優先的時代,App已成為企業核心數據載體,然而??傳統爬蟲技術??在App數據獲取上面臨三大難題: ??協議層屏障??:加密HTTPS、SSL Pinning等技術阻斷中間人攻擊??渲染層障礙??:React Native、Flutter等跨平臺框架使DOM解析…

【LeetCode 熱題 100】560. 和為 K 的子數組——(解法一)前綴和+暴力

Problem: 560. 和為 K 的子數組 題目&#xff1a;給你一個整數數組 nums 和一個整數 k &#xff0c;請你統計并返回 該數組中和為 k 的子數組的個數 。子數組是數組中元素的連續非空序列。 【LeetCode 熱題 100】560. 和為 K 的子數組——&#xff08;解法二&#xff09;前綴和…

android車載開發之HVAC

目前主要在做車載hvac的開發&#xff0c;主要的一些功能主要是hvac&#xff0c;座椅&#xff0c;香氛&#xff0c;設置等的一些模塊&#xff0c;具體模塊下&#xff0c;比如 1.空調 ac&#xff0c;智能模式&#xff08;極速降溫&#xff0c;極速采暖&#xff0c;智能除味&…

深度學習 Diffusers 庫(自留)

&#xff08;本文將圍繞 安裝Diffusers庫及其依賴、理解Diffusers核心概念&#xff1a;Pipeline, Model, Scheduler 、使用預訓練模型進行推理&#xff08;文生圖、圖生圖等&#xff09; 、 自定義模型和調度器 、訓練自己的擴散模型&#xff08;可選&#xff0c;需要大量資源&…

【VPC技術】基礎理論篇

文章目錄 概述相關基礎核心知識軟件定義網絡SDNOverlay 技術 安全組概述 參考博客 &#x1f60a;點此到文末驚喜?? 概述 相關基礎 基本概念 虛擬私有云VPC&#xff1a;是一個隔離的網絡環境&#xff0c;每個VPC擁有專屬的IP地址范圍&#xff08;CIDR&#xff09;、路由表、…

在 RK3588 Ubuntu 上編譯 eglinfo:全流程實戰 + 常見報錯修復

dv1/eglinfo 是一個開源的 EGL 信息檢測工具&#xff0c;廣泛用于 OpenGL ES 圖形棧調試、驅動驗證和嵌入式平臺圖形支持排查。在 Rockchip RK3588 上編譯該工具可以協助我們確認 EGL DRM 是否配置正確&#xff0c;尤其在無窗口系統&#xff08;如 eglfs、framebuffer&#xf…

開源推薦:基于前后端分離架構的WMS倉儲管理系統

開源推薦&#xff1a;基于前后端分離架構的WMS倉儲管理系統 &#x1f525; 在線演示地址&#xff1a;https://tob.toolxq.com/wms/wms.html 點擊上方鏈接可直接體驗系統功能和界面&#xff0c;無需安裝部署 前言 在企業數字化轉型的浪潮中&#xff0c;倉儲管理系統&#xff08…

Redis中List類型常見的操作命令有哪些?

Redis中List類型是一個字符串列表&#xff0c;這里是一些常見的命令&#xff1a; 1&#xff09;lpush:將一個或多個值插入到列表頭部。列表不存在&#xff0c;一個新的列表會被創建。 2&#xff09;rpush:將一個或多個值插入到列表尾部。 3&#xff09;lpop:移除并返回列表頭…