??樊梓慕:個人主頁
???個人專欄:《C語言》《數(shù)據(jù)結(jié)構(gòu)》《藍橋杯試題》《LeetCode刷題筆記》《實訓項目》《C++》《Linux》《算法》
??每一個不曾起舞的日子,都是對生命的辜負
目錄
前言
1.C語言文件IO
1.1C語言文件IO接口匯總?
1.2當前路徑指的是什么?
?1.3stdin、stdout、stderr
2.系統(tǒng)文件IO
2.1open
參數(shù)const char* pathname
參數(shù)int flags
*位圖方式傳參
參數(shù)mode_t mode
返回值int fd『 簡要理解文件描述符』
2.2close
2.3write?
2.4read
前言
進程周邊的相關(guān)內(nèi)容暫時告一段落,下面我們開始學習文件部分。
學習『 系統(tǒng)文件IO』之前,我會與大家先復習一下C語言部分文件IO的相關(guān)接口,為后面的學習作『 鋪墊』。系統(tǒng)文件IO部分,本篇文章會講解『 基本的系統(tǒng)調(diào)用』:open()、close()、read()、write(),有關(guān)參數(shù)傳遞涉及到『 位圖方式傳遞』,這部分以前沒有學習過,博主也會拿出來簡單的學習一下。
歡迎大家??收藏??以便未來做題時可以快速找到思路,巧妙的方法可以事半功倍。
=========================================================================文章來源地址http://www.zghlxwxcb.cn/news/detail-821074.html
GITEE相關(guān)代碼:??fanfei_c的倉庫??
=========================================================================
1.C語言文件IO
1.1C語言文件IO接口匯總?
在學習C語言期間,我們學習過一些C語言封裝的文件接口:
![]() |
打開文件 |
![]() |
關(guān)閉文件 |
![]() |
寫入一個字符 |
![]() |
讀取一個字符 |
![]() |
寫入一個字符串 |
![]() |
讀取一個字符串 |
![]() |
格式化寫入數(shù)據(jù) |
![]() |
格式化讀取數(shù)據(jù) |
![]() |
向二進制文件寫入數(shù)據(jù) |
![]() |
從二進制文件讀取數(shù)據(jù) |
![]() |
設(shè)置文件指針的位置 |
![]() |
計算當前文件指針相對于起始位置的偏移量 |
![]() |
設(shè)置文件指針到文件的起始位置 |
![]() |
判斷文件操作過程中是否發(fā)生錯誤 |
![]() |
判斷文件指針是否讀取到文件末尾 |
本篇文章不會完全的講解以上C語言文件接口,想要詳細了解的同學可以『 點擊以下內(nèi)容』跳轉(zhuǎn)到博主的有關(guān)C語言文件IO的博客。
『 樊梓慕』文件操作——CSDN
1.2當前路徑指的是什么?
當我們利用C語言IO接口創(chuàng)建文件時,生成的文件默認在『 當前路徑』,可當前路徑具體指的是誰的路徑呢?
- 『 文件是由進程創(chuàng)建』,所以文件的當前路徑也是進程的當前路徑。
在之前學習進程的部分,我們已經(jīng)聊過有關(guān)話題,當前路徑指的是進程在啟動時,會保存當前目錄的路徑,保存到『 /proc/[pid]/cwd』中,該路徑就是進程的當前路徑。
?1.3stdin、stdout、stderr
在之前學習時,我們提到過一個概念:『 Linux下一切皆文件』 ,也就是說鍵盤、顯示器都是文件,這很好理解,我們向普通文件寫入,本質(zhì)上就是向磁盤寫入數(shù)據(jù),那將對象改為顯示器,是不是就是打印了?
但是,向文件寫入我們一般這么操作:
FILE* fp = fopen("log.txt", "w");
fputs("hello world\n", fp);
可是打印我們從未『 打開』顯示器文件,也從未『 傳遞』過流參數(shù):
printf("hello world\n");
這也就說明了:
進程在運行的時候都會『 默認打開』三個輸入輸出流,即標準輸入流、標準輸出流以及標準錯誤流,對應(yīng)到C語言當中就是stdin、stdout以及stderr。
其中,標準輸入流對應(yīng)的設(shè)備就是鍵盤,標準輸出流和標準錯誤流對應(yīng)的設(shè)備都是顯示器。
所以,我們想要實現(xiàn)打印的功能,也可以這樣寫:
fputs("hello world\n", stdout);
stdin、stdout以及stderr是C標準庫下的標準輸入輸出錯誤流,其他語言如C++也有對應(yīng)的標準輸入輸出錯誤流:cin、cout和cerr。
2.系統(tǒng)文件IO
?C程序可以直接對硬件進行寫入么?
在之前學習的時候,關(guān)于操作系統(tǒng)我們有過這樣一張圖:
什么意思?
程序不可能也不可以越過操作系統(tǒng)直接操作硬件,還記得『 系統(tǒng)調(diào)用』么?
?也就是說C標準庫中的文件IO接口一定『 封裝了系統(tǒng)調(diào)用』,所以才能利用fopen()、fputs()等函數(shù)對文件進行操作。
那接下來我們就來學習文件IO的系統(tǒng)調(diào)用。
2.1open
?open是打開文件的系統(tǒng)調(diào)用接口。
int open(const char *pathname, int flags, mode_t mode);
參數(shù)const char* pathname
代表要打開或創(chuàng)建的目標文件。?
- 若pathname以路徑的方式給出,則當需要創(chuàng)建該文件時,就在pathname路徑下進行創(chuàng)建。
- 若pathname以文件名的方式給出,則當需要創(chuàng)建該文件時,默認在當前路徑下進行創(chuàng)建。
參數(shù)int flags
代表文件的打開方式。
參數(shù) | 含義 |
---|---|
O_RDONLY | 以只讀的方式打開文件 |
O_WRNOLY | 以只寫的方式打開文件 |
O_APPEND | 以追加的方式打開文件 |
O_RDWR | 以讀寫的方式打開文件 |
O_CREAT | 當目標文件不存在時,創(chuàng)建文件 |
傳遞方式介紹:
例如:以只寫的方式打開文件,當目標文件不存在時自動創(chuàng)建文件,則參數(shù)設(shè)置如下:
O_WRONLY | O_CREAT
為什么這么傳遞??
*位圖方式傳參
?先寫一段代碼:
#define ONE 1
#define TWO (1<<1)
#define THREE (1<<2)
#define FOUR (1<<3)
#define FIVE (1<<4)
void Print(int flag)
{
if(flag & ONE) printf("1\n");
if(flag & TWO) printf("2\n");
if(flag & THREE) printf("3\n");
if(flag & FOUR) printf("4\n");
if(flag & FIVE) printf("5\n");
}
int main()
{
Print(ONE);
printf("----------------------\n");
Print(TWO);
printf("----------------------\n");
Print(ONE|TWO);
printf("----------------------\n");
Print(THREE|FOUR|FIVE);
printf("----------------------\n");
Print(ONE|TWO|THREE|FOUR|FIVE);
}
?根據(jù)代碼中的宏定義,這些宏的特點就是所有位加起來只有一個1。?
?Print函數(shù)中五個if中的判斷條件其實就是判斷參數(shù)哪個位為1,如果傳的是ONE,那么ONE與ONE&得到的就是1,為真就打印1,其余的都為假,不打印。
當帶上|操作符后,相當于把兩個參數(shù)的1位合并到一起,比如ONE|TWO得到的就是0011,所以在Print中就會滿足兩個條件flag & ONE 和 flag & TWO。
這就是位圖方式傳參的基本思想。
放到flags中呢?
#define O_RDONLY 0000
#define O_WRONLY 0001
#define O_RDWR 0010
#define O_CREAT 0100
之后通過&運算:
int open(arg1, arg2, arg3){
if (arg2&O_RDONLY){
//設(shè)置了O_RDONLY選項
}
if (arg2&O_WRONLY){
//設(shè)置了O_WRONLY選項
}
if (arg2&O_RDWR){
//設(shè)置了O_RDWR選項
}
if (arg2&O_CREAT){
//設(shè)置了O_CREAT選項
}
//...
}
所以如果arg2=O_CREAT |?O_WRONLY,即arg2=0101,arg2 &?O_WRONLY =1 && arg2 &?O_CREAT =1就達到了『 以只寫的方式打開文件,當目標文件不存在時自動創(chuàng)建文件』的目的。
這就是『 位圖方式傳參』。
參數(shù)mode_t mode
代表創(chuàng)建文件的默認權(quán)限。
例如:將mode設(shè)置為0666,則創(chuàng)建出來的文件權(quán)限如下:
-rw-rw-rw-
但『 實際上』創(chuàng)建出來文件的權(quán)限值還會受到umask(文件默認掩碼)的影響。
實際創(chuàng)建出來文件的權(quán)限為:mode減去對應(yīng)位的umask值。
umask的默認值默認為0002,所以當我們設(shè)置mode值為0666時實際創(chuàng)建出來文件的權(quán)限為0664。
若想創(chuàng)建出來文件的權(quán)限值不受umask的影響,則需要在創(chuàng)建文件前使用umask函數(shù)將文件默認掩碼設(shè)置為0。
umask(0); //將文件默認掩碼設(shè)置為0
如果不需要創(chuàng)建新的文件,則使用兩個參數(shù)的open即可。?
返回值int fd『 簡要理解文件描述符』
代表打開文件的『 文件描述符』。
- fd>0:返回的是文件描述符。
- fd==-1:代表打開文件失敗。
一個進程可以打開多個文件:????????
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{
umask(0);
int fd1 = open("log1.txt", O_RDONLY | O_CREAT, 0666);
int fd2 = open("log2.txt", O_RDONLY | O_CREAT, 0666);
int fd3 = open("log3.txt", O_RDONLY | O_CREAT, 0666);
int fd4 = open("log4.txt", O_RDONLY | O_CREAT, 0666);
int fd5 = open("log5.txt", O_RDONLY | O_CREAT, 0666);
printf("fd1:%d\n", fd1);
printf("fd2:%d\n", fd2);
printf("fd3:%d\n", fd3);
printf("fd4:%d\n", fd4);
printf("fd5:%d\n", fd5);
return 0;
}
?為什么是從3開始呢?
我們剛才講進程默認會打開三個輸入輸出流:標準輸入流、標準輸出流、標準錯誤流。
所以0、1、2分別代表了它們。
從而我們得到文件描述符的分配規(guī)則:
找到當前沒有被使用的最小的下標,作為新的文件描述符。?
2.2close
close是關(guān)閉文件的系統(tǒng)調(diào)用接口。
int close(int fd);//參數(shù)fd是文件描述符
- 關(guān)閉文件成功返回0;
- 關(guān)閉文件失敗返回-1。
2.3write?
write是寫入文件的系統(tǒng)調(diào)用接口。
ssize_t write(int fd, const void *buf, size_t count);
功能:將buf位置開始向后count字節(jié)的數(shù)據(jù)寫入文件描述符為fd的文件當中。
- 寫入成功,返回寫入數(shù)據(jù)的字節(jié)個數(shù)。
- 寫入失敗,返回-1。
例如:?
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
if (fd < 0){
perror("open");
return 1;
}
const char* msg = "hello syscall\n";
for (int i = 0; i < 5; i++){
write(fd, msg, strlen(msg));
}
close(fd);
return 0;
}
2.4read
read是讀取文件的系統(tǒng)調(diào)用接口。
ssize_t read(int fd, void *buf, size_t count);
功能:從文件描述符為fd的文件讀取count字節(jié)的數(shù)據(jù)到buf位置當中。
- 讀取成功,返回讀取數(shù)據(jù)的字節(jié)個數(shù)。
- 讀取失敗,返回-1。
例如:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd = open("log.txt", O_RDONLY);
if (fd < 0){
perror("open");
return 1;
}
char ch;
while (1){
ssize_t s = read(fd, &ch, 1);
if (s <= 0){
break;
}
write(1, &ch, 1);
//向文件描述符為1的文件寫入數(shù)據(jù),即向標準輸出流(顯示器)寫入數(shù)據(jù)
}
close(fd);
return 0;
}
當然對于文件管理來說還有很多需要講解的細節(jié),博主會放到下一篇文章中詳細講解,下一篇文章會深入學習『 Linux系統(tǒng)是如何管理文件的』,『 文件描述符在其中又扮演了怎樣的角色』,『 怎么理解Linux下一切皆文件』等等內(nèi)容,本篇文章只是文件部分的簡單開頭,主要目的是為了『 作鋪墊』,更多內(nèi)容,請持續(xù)關(guān)注博主Linux系列文章。?
=========================================================================
如果你對該系列文章有興趣的話,歡迎持續(xù)關(guān)注博主動態(tài),博主會持續(xù)輸出優(yōu)質(zhì)內(nèi)容
??博主很需要大家的支持,你的支持是我創(chuàng)作的不竭動力??
??~ 點贊收藏+關(guān)注 ~??文章來源:http://www.zghlxwxcb.cn/news/detail-821074.html
=========================================================================
到了這里,關(guān)于【Linux】文件周邊001之系統(tǒng)文件IO的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!