Linux命令【四】文件+虛擬內存+常用系統函數

File*其實是一個結構體

  • 文件描述符FD:索引到對應的磁盤文件
  • 文件讀寫位置指針FP_POS,如果同時讀寫需要注意文件指針的位置
  • I/O緩沖區BUFFER:保存內存指針,默認大小是8kb,用于減小我們對硬盤操作的次數。因為我們對硬盤的操作是ms級別的,而我們電子設備的操作是ns級別的。
  • 刷新緩沖區到硬盤上:fflush、緩沖區已滿、文件正常關閉、return main、exit main
  • Linux系統函數沒有緩沖區,C庫函數自帶緩存

在Linux中,inode保存文件的屬性,里面有一個結構體struct stat,其中記錄了文件的各種信息,但是沒有保存文件名。
文件名保存在denty(目錄項)中,每一個文件名對應一個inode編號。每一個硬鏈接都是一個denty

以Linux32為系統為例:

  • 文件描述符:
    • Linux為每一個運行的程序分配0-4G的內存
    • 0-3G是用戶區,3-4G是內核區,內核區不允許用戶去訪問
    • 文件描述符位于內核區中的PCB進程控制塊中,0-1023,每個位置儲存一個文件。0\1\2默認是打開的,分別是STDIN_FiLENO 、STDOUT_FILENO 、STDERR_FILENO,每打開一個新文件,會多儲存一個文件描述符。是一個棧

查看文件格式:file 文件

虛擬地址

用戶區:0-3G

  • 受保護的內存(0-4K)none指針指向這個位置
  • ELF段
    • .text 代碼段,二進制機器指令,包含main函數、靜態庫
    • .rodata段 和.text一樣都是ro(只讀)權限,在鏈接的時候完成數據段合并
    • .data段 已經初始化的全局變量
    • .bss未初始化的全局變量,和.data段一樣是rw(讀寫)權限
  • 堆空間:保存全局變量,用malloc或者new在堆上分配內存
  • 共享庫: 動態庫,對庫的調用是相對的地址。
  • 棧空間:從上面開始分配內存,保存局部變量
  • 命令行參數:main函數的參數
  • 環境變量:env查看

CPU使用虛擬地址與物理空間映射的作用:

  • 方便編譯器和操作系統安排程序的地址分布:程序可以使用一系列連續的虛擬地址訪問內存中不連續的內存緩沖區
  • 方便進程之間的隔離:不同進程之間彼此隔離,一個進程中的代碼無法更改正在另一項進程的物理內存
  • 方便OS使用內存:程序可以使用一系列虛擬地址來訪問大于可用物理內存的內存緩沖區。當物理內存的供應量變小時,內存管理器會將物理內存頁(通常為4KB)保存到此案文件。數據或代碼頁會根據需要在物理內存和磁盤之間移動

printf函數

printf函數
調用write函數將文件描述符傳遞
應用層運行write函數
系統調用sys_write()函數,從用戶態轉化為內核態
內核層設備驅動函數

常用的系統應用函數

man 章節號 需要查找的函數 // 查看Linux手冊中的函數

open函數

int open(const char *pathname, int flags);// The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY,  or O_RDWR.  These request opening the file read-only, write-only,or read/write, respectively.int open(const char *pathname, int flags, mode_t mode);
//mode:給創建文件設定訪問權限

返回一個文件描述符,-1意思是發生了錯誤,errno會被賦予錯誤信息,使用需要包含errno.h

錯誤宏定義的位置:
第1-34個錯誤:usr/incclude/asm-generic/errno-base.h
第35-133個錯誤:/usr/include/asm-generic/errno.h

void perror(const char *s)用來將上一個函數發生錯與原因輸出到標準設備

編寫函數的時候可以使用章節+ shift+k查看函數的man文檔

例如:

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>	//open的頭文件
#include<unistd.h>	//close的頭文件
#include<stdlib.h>	//exit的頭文件
#include<stdio.h>	//perror的頭文件
int main()
{int fd;	//用于保存文件描述符fd = open("main.c",O_RDWR);if(fd==-1){perror("open file");exit(1);}//創建新文件fd = open("newfile.c",O_RDWR | O_CREAT,777);//實際上文件的屬性是775,因為本地有一個掩碼,給定的權限將會和掩碼有一個取反按位與的操作,實際上相當于減法//nmask獲取本地掩碼printf("新文件的文件描述符:%d\n",fd);//關閉文件int ret = close(fd);if(ret==-1){perror("close file");exit(1);}elseprintf("ret=%d\n",ret);return 0;
}

獲取本地掩碼:umask
修改本地掩碼:umask xxxx
O_CREAT需要將掩碼取反再將權限按位與

通過O_CREAT 與O_EXCL和起來使用判斷文件是否已經存在,例如:

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>	//open的頭文件
#include<unistd.h>	//close的頭文件
#include<stdlib.h>	//exit的頭文件
#include<stdio.h>	//perror的頭文件
int main()
{int fd;	//用于保存文件描述符
/*fd = open("main.c",O_RDWR);if(fd==-1){perror("open file");exit(1);}//創建新文件fd = open("newfile.c",O_RDWR | O_CREAT,777);//實際上文件的屬性是775,因為本地有一個掩碼,給定的權限將會和掩碼有一個取反按位與的操作,實際上相當于減法//nmask獲取本地掩碼printf("新文件的文件描述符:%d\n",fd);
*/fd = open("myhelloc.c",O_RDWR|O_CREAT|O_EXCL , 777);if(fd==-1){perror("open file");exit(1);}
//關閉文件int ret = close(fd);if(ret==-1){perror("close file");exit(1);}elseprintf("ret=%d\n",ret);return 0;
}

文件清空、截斷為0O_TRUNC

一定要注意對返回值做一個判斷,這樣出錯的時候就能知道哪里出錯。

read()

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

返回值:

  • -1 讀文件失敗,設置errno
  • 0文件讀取了
  • x 讀取了x個字符

write()

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

lseek()

#include <sys/types.h>#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
whence as follows:SEEK_SETThe file offset is set to offset bytes.SEEK_CURThe file offset is set to its current location plus offset bytes.SEEK_ENDThe file offset is set to the size of the file plus offset bytes.

使用舉例:將一個文件的內容拷貝到另一個文件

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>	//Open
#include<unistd.h>	//Close
#include<stdlib.h>	//exit
#include<stdio.h>	//perror
#include<string.h>
#define MAXN 1005
char buffer[MAXN];	//緩沖區
int fd_in,fd_out;	//用于保存文件描述符void Open()
{fd_in=open("file_in",O_RDONLY);if(fd_in == -1){perror("Open fin:");exit(1);}//fd_out=open("file_out",O_WRONLY | O_CREAT | O_EXCL,0777);fd_out=open("file_out",O_WRONLY | O_CREAT,0644);if(fd_out == -1){perror("Open fout:");exit(1);}
}void Close()
{int ret=close(fd_in);if(ret==-1){perror("Close fin");exit(1);}if(ret==-1){perror("Close fout");exit(1);}
}void Work()
{int cnt=read(fd_in,buffer,MAXN);if(-1==cnt){printf("讀取文件失敗");}while(cnt)	//沒有讀取到文件末尾{write(fd_out,buffer,cnt);cnt=read(fd_in,buffer,MAXN);}
}	
int main()
{Open();Work();Close();
}

經驗:

  • open函數如果使用O_CREAT參數,則需要指定使用權限(八進制數字,需要在權限前面加0),如果只使用O_CREATO_RDWR參數配合,如果文件已經存在就會打開之前的文件,不會創建新文件,如果再配合O_EXCL參數,那么如果已經存在文件就會報錯。
  • 文件的實際權限是指定權限減去掩碼
  • 不要眼高手低,即使看起來比較簡單的東西還是需要多動手實踐,才能發現自己的問題

lseek

 #include <sys/types.h>#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);
lseek()  repositions the file offset of the open file description associated
with the file descriptor fd to the argument offset according to  the  direc‐
tive whence as follows:SEEK_SETThe file offset is set to offset bytes.SEEK_CURThe file offset is set to its current location plus offset bytes.SEEK_ENDThe file offset is set to the size of the file plus offset bytes.
  • 獲取文件長度ret=lseek(fd,0,SEEK_END)
  • 文件拓展:只能向后拓展文件,不能向前
int ret=lseek(fd,2000,SEEK_END);
//文件拓展需要最后做一次寫操作,隨便寫一點東西就可以
//得到一個空洞文件,先得到預定大小的文件然后使用多線程操作
write(fd,"a",1);

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

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

相關文章

Python3列表

操作&#xff1a;索引、切片、加、乘、檢查成員、確定序列長度、確定最大最小元素 定義&#xff1a; 列表名 [元素]下標列表名[x] 截取:列表名[x:y] 更新&#xff1a; list[x]y 或者使用append()方法添加列表項刪除&#xff1a; del list[x]常用操作&#xff1a; 截取與…

Linux驚群效應詳解(最詳細的了吧)

https://blog.csdn.net/lyztyycode/article/details/78648798?locationNum6&fps1 linux驚群效應詳細的介紹什么是驚群&#xff0c;驚群在線程和進程中的具體表現&#xff0c;驚群的系統消耗和驚群的處理方法。1、驚群效應是什么&#xff1f;驚群效應也有人叫做雷鳴群體效應…

epoll原理詳解(最清晰)

https://blog.csdn.net/lyztyycode/article/details/79491419我只是把內容搬運過來做個記錄&#xff0c;方便自己以后回頭看。第一部分&#xff1a;select和epoll的任務關鍵詞&#xff1a;應用程序 文件句柄 用戶態 內核態 監控者要比較epoll相比較select高效在什么地方&#x…

Linux命令【五】系統函數

系統文件函數 stat函數 指針如果沒有const一般表示傳出參數&#xff0c;如果加const表示傳入參數 struct stat dev_t st_dev文件設備編號ino_t st_ino節點 inode號是唯一的&#xff0c;每個inode節點的大小一般是128字節活著256字節&#xff0c;一般文件每2KB就設置一個ino…

生產者-消費者模型的兩種實現方式

https://www.cnblogs.com/caolicangzhu/p/7086176.html本文主要來總結生產者-消費者模型的代碼實現,至于其原理,請大家自行百度. 一、基于鏈表的生產-消費模型(條件變量)我們以鏈表為例,生產者進行頭部插入,消費者進行頭部刪除,因此,先將鏈表相關操作封裝為LinkList.h,具體代碼…

Linux系統【一】CPU+MMU+fork函數創建進程

切板中的內容輸出到文件### 進程相關概念 程序&#xff1a;編譯好的二進制文件&#xff0c;在磁盤上&#xff0c;不占用系統資源&#xff08;不包括磁盤&#xff09;。&#xff08;劇本&#xff09; 進程&#xff1a;占用系統資源&#xff0c;是程序的一次運行。&#xff08;戲…

Ubuntu卸載軟件

用過使用dpkg軟件管理工具得到所有已經安裝的軟件&#xff0c;如果不清楚軟件的全名可以使用grep命令進行查找 然后再使用sudo apt-get remove --purge 軟件名卸載軟件&#xff08;--purge參數會刪除配置文件&#xff0c;刪的干凈一些&#xff09; 例如&#xff1a;

一個重要且實用的signal---SIGCHLD

https://blog.csdn.net/lyztyycode/article/details/78150805SIGCHLD(修改)因為筆者之前的文章里面有錯誤&#xff0c;今天發現&#xff0c;立馬做個修改。在下面我的一段關于sigchld信號相對于直接調用wait函數的好處時&#xff0c;我說調用wait函數要一直檢測子進程是否執行完…

數據結構實驗之鏈表七:單鏈表中重復元素的刪除

https://blog.csdn.net/blessingxry/article/details/794455111.知識點&#xff1a;逆序建立鏈表&#xff0b;節點刪除 2.題意&#xff1a;按照數據輸入的相反順序&#xff08;逆位序&#xff09;建立一個單鏈表&#xff0c;并將單鏈表中重復的元素刪除&#xff08;值相同的元素…

Python3函數和代碼復用

函數的定義 def 函數名([參數列表]):注釋函數體注意事項 函數形參不需要聲明類型&#xff0c;可以使用return語句在結束函數執行的同時返回任意類型的值&#xff0c;函數返回值類型與return語句返回表達式i的類型一致 即使該函數不需要接受任何參數&#xff0c;也必須保留一堆…

一文說盡C++賦值運算符重載函數(operator=)

http://www.cnblogs.com/zpcdbky/p/5027481.html在前面&#xff1a;關于C的賦值運算符重載函數(operator)&#xff0c;網絡以及各種教材上都有很多介紹&#xff0c;但可惜的是&#xff0c;內容大多雷同且不全面。面對這一局面&#xff0c;在下在整合各種資源及融入個人理解的基…

Python a和a[:]的區別

簡單來講a[:]是深復制&#xff0c;a是淺復制&#xff0c;相當于賦值a的話是賦值了指針&#xff0c;賦值a[:]相當于復制了a對應的那段空間 例如&#xff1a; a [1,1,1,1,1,1]for x in a:if x1:a.remove(x)print(a)運行結果&#xff1a; remove操作是移除序列中第一個x元素。…

約瑟夫環(c語言程序完整版)

https://blog.csdn.net/m_hahahaha1994/article/details/51742453約瑟夫環&#xff08;約瑟夫問題&#xff09;是一個數學的應用問題&#xff1a;已知n個人&#xff08;以編號1&#xff0c;2&#xff0c;3…n分別表示&#xff09;圍坐在一張圓桌周圍。從編號為k的人開始報數&am…

Linux系統【二】exec族函數及應用

文件描述符 文件描述符表是一個指針數組&#xff0c;文件描述符是一個整數。 文件描述符表對應的指針是一個結構體&#xff0c;名字為file_struct&#xff0c;里面保存的是已經打開文件的信息 需要注意的是父子進程之間讀時共享&#xff0c;寫時復制的原則是針對物理地址而言…

白話C++系列(27) -- RTTI:運行時類型識別

http://www.cnblogs.com/kkdd-2013/p/5601783.htmlRTTI—運行時類型識別 RTTI&#xff1a;Run-Time Type Identification。 那么RTTI如何來體現呢&#xff1f;這就要涉及到typeid和dynamic_cast這兩個知識點了。為了更好的去理解&#xff0c;那么我們就通過一個例子來說明。這個…

使用頭文件的原因和規范

原因 通過頭文件來調用庫功能。在很多場合&#xff0c;源代碼不便&#xff08;或不準&#xff09;向用戶公布&#xff0c;只 要向用戶提供頭文件和二進制的庫即可。用戶只需要按照頭文件中的接口聲明來調用庫 功能&#xff0c;而不必關心接口怎么實現的。編譯器會從庫中提取相應…

轉圈踢人問題

https://www.cnblogs.com/lanxuezaipiao/p/3339603.html 有N個人圍一圈依次報數&#xff0c;數到3的倍數的人出列&#xff0c;問當只剩一個人時他原來的位子在哪里&#xff1f; 解答&#xff1a;經典的轉圈踢人問題&#xff0c;好吧專業一點&#xff0c;約瑟夫環問題&#xff0…

Linux系統【三】回收子進程

孤兒進程 父進程先于子進程結束&#xff0c;則子進程成為孤兒進程&#xff0c;子進程的父進程成為init進程&#xff0c;則稱init進程領養孤兒進程。現在好像是用戶進程中的system進程。 僵尸進程 進程終止&#xff0c;父進程不進行回收&#xff0c;自己成殘留資源(PCB)存放在…

string類的基本實現

https://blog.csdn.net/qq_29503203/article/details/52265829在面試中面試官常常會讓你寫出string類的基本操作&#xff0c;比如&#xff1a;構造函數&#xff0c;析構函數&#xff0c;拷貝構造等等.下面是除此之外的一些操作&#xff0c;希望可以幫助你更好的理解string以便以…

Python3常用數據結構

Python3中有三種組合數據類型&#xff0c;分別為&#xff1a; 序列類型&#xff1a;字符串&#xff08;str&#xff09;、元組&#xff08;tuple&#xff09;、列表&#xff08;list&#xff09;集合類型&#xff1a;集合&#xff08;set&#xff09;映射類型&#xff1a;字典…