linux系統調用open、write、close、read以及stat函數詳解

學習筆記 參考鏈接1 、參考鏈接2以及百度百科
在進行C語言學習的時候我們了解到了C語言相關的一些IO操作,如fopen,fwrite,fread,fprintf,fclose等相關函數,他們都是由C庫函數提供的一些函數,是將操作系統的系統調用加以封裝,雖說Linux是由C語言實現的,但為了使我們更加的了解Linux,就需要了解更接近與底層的一些IO操作,因此就需要來了解下基本的系統調用—open,write,read,close
首先我們來了解下open,write,read,close的系統調用

open

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags, mode_t mode);

open有三個參數
pathname:要打開或創建的目標文件名
flags:對文件進行多種操作也就有有多個參數,這多個參數可以進行或運算,即就是flags
參數:
O_RDONLY:只讀打開
O_WRONLY:只寫打開
O_RDWR:讀,寫打開
O_CREAT:若文件不存在,創建文件
O_APPEND:追加寫
參數1,2,3,必須制定一個且只能制定一個,使用參數4,必須使用open的第三個參數mode:新文件的訪問權限
返回值:成功:新打開文件的文件描述符(fd)
失敗:-1

write

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

fd:文件描述符
buf:寫入的緩沖區
count:寫的字符長度,也就是看你需要寫多少
返回值:
如果順利write()會返回實際寫入的字節數。當有錯誤發生時則返回-1,錯誤代碼存入errno中。
read

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

fd:文件描述符
buf:讀入的緩沖區
count:寫的字符長度,也就是看你需要寫多少
返回值
如果順利read()會返回實際寫入的字節數。當有錯誤發生時則返回-1,錯誤代碼存入errno中。
close

#include <unistd.h>
int close(int fd);

close的參數就相對簡單了,這一個操作是不能遺漏的,只要了使用fd就必須close它
在這幾個函數中都涉及到了關鍵的參數fd,因此要了解這幾個函數,就必須先了解下文件描述符(fd)。
什么是文件描述符,這是一個相對抽象的概念,我們先來看看下面這張圖
這里寫圖片描述
在PCB結構體中存在一個files指針,它指向一個file_struct結構體,而在file_struct結構體中存在一個file* fd數組,這個數組里面存放的是file指針,用來指向不同的file文件,而fd就可以理解為這個指針數組的下標,因此要打開一個文件,我們就可以拿到該文件的fd就可以了。
fd的分配原則:
files_struct數組當中,使用沒有被使用的最小下標,作為新的文件描述符。
操作系統默認使用了該數組的前三個元素,0號下標指向標準輸入(stdin),1號下標指向標準輸出(stdout),2號下標指向標準錯誤(stderr)。
因此正常情況下,新的fd都是從3開始的,但如果我們關閉了默認的fd,新的文件的fd就從關閉的fd處開始。
說到了fd,我們就不得不來區分下FILEfd
FILE是C庫當中提供的一個結構體,而fd是系統調用,更加接近于底層,因此FILE中必定封裝了fd。
我們可以來看看FILE的結構體:
typedef struct _IO_FILE FILE;在/usr/include/stdio.h
它的結構體中有這么一段

struct _IO_FILE {int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags//緩沖區相關/* The following pointers correspond to the C++ streambuf protocol. *//* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */char* _IO_read_ptr;   /* Current read pointer */char* _IO_read_end;   /* End of get area. */char* _IO_read_base;  /* Start of putback+get area. */char* _IO_write_base; /* Start of put area. */char* _IO_write_ptr;  /* Current put pointer. */char* _IO_write_end;  /* End of put area. */char* _IO_buf_base;   /* Start of reserve area. */char* _IO_buf_end;    /* End of reserve area. *//* The following fields are used to support backing up and undo. */char *_IO_save_base; /* Pointer to start of non-current get area. */char *_IO_backup_base;  /* Pointer to first valid character of backup area */ char *_IO_save_end; /* Pointer to end of non-current get area. */struct _IO_marker *_markers;struct _IO_FILE *_chain;int _fileno;//fd的封裝

可以看到int_fileno就是對fd的封裝,在這一部分的開頭有一大段跟緩沖區相關的內容,為什么要諾列出它呢,首先可以來看一個很詭異的例子:

#include <stdio.h>                                                            #include <string.h>#include <unistd.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>int main(){const char *msg1 = "hello printf\n";const char *msg2 = "hello fwrite\n";const char *msg3 = "hello write\n";printf(msg1);fwrite(msg2, 1, strlen(msg2), stdout);write(1, msg3, strlen(msg3));fork();return 0;}

運行結果:

[rlh@localhost test]$ ./hello
hello printf 
hello fwrite 
hello write

但當我們對進程實現輸出重定向,你就會發現詭異的事情:

[rlh@localhost test]$ ./hello > file
[rlh@localhost test]$ cat file 
hello write 
hello printf 
hello fwrite 
hello printf 
hello fwrite

這是為什么呢,這是跟C庫的緩沖數據有關,C庫緩沖數據分為三種(1)、無緩沖(2)、行緩沖(3)、全緩沖。

行緩沖就是往顯示器上寫,全緩沖就是往文件里寫。

在上面的現象中,write不受影響是因為它屬于系統調用,沒有緩沖區,而printf和fwrite會自帶緩沖區,當發生重定向到普通文件的時候,它就會從行緩沖轉變為全緩沖,也就是會往文件里面寫寫,但是我們緩沖區里的數據,即使fork也不會立即被刷新,當進程退出后會統一刷新,寫入文件,但是fork的時候會發生寫時拷貝,也就是當父進程準備刷新的時候,子進程就已經有了一份相同的數據,所以就會產生上面的現象。

了解下重定向。
重定向分為三種:
輸出重定向(>) 也就是關閉fd為1下標所指向的內容
輸入重定向(<) 同理就是關閉fd為0下標所指向的內容
追加重定向(>>) 后面多一個追加選項

stat函數

#include <sys/stat.h>
#include <unistd.h>
int stat(const char *file_name, struct stat *buf);

函數說明: 通過文件名filename獲取文件信息,并保存在buf所指的結構體stat中
返回值: 執行成功則返回0,失敗返回-1,錯誤代碼存于errno

錯誤代碼:
ENOENT 參數file_name指定的文件不存在
ENOTDIR 路徑中的目錄存在但卻非真正的目錄
ELOOP 欲打開的文件有過多符號連接問題,上限為16符號連接
EFAULT 參數buf為無效指針,指向無法存在的內存空間
EACCESS 存取文件時被拒絕
ENOMEM 核心內存不足
ENAMETOOLONG 參數file_name的路徑名稱太長
eg:

#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>int main() {struct stat buf;stat("/etc/hosts", &buf);printf("/etc/hosts file size = %d/n", buf.st_size);
}
struct stat {dev_t         st_dev;       //文件的設備編號ino_t         st_ino;       //節點mode_t        st_mode;      //文件的類型和存取的權限nlink_t       st_nlink;     //連到該文件的硬連接數目,剛建立的文件值為1uid_t         st_uid;       //用戶IDgid_t         st_gid;       //組IDdev_t         st_rdev;      //(設備類型)若此文件為設備文件,則為其設備編號off_t         st_size;      //文件字節數(文件大小)unsigned long st_blksize;   //塊大小(文件系統的I/O 緩沖區大小)unsigned long st_blocks;    //塊數time_t        st_atime;     //最后一次訪問時間time_t        st_mtime;     //最后一次修改時間time_t        st_ctime;     //最后一次改變時間(指屬性)
};

先前所描述的st_mode 則定義了下列數種情況:

 S_IFMT   0170000    文件類型的位遮罩S_IFSOCK 0140000    scoketS_IFLNK 0120000     符號連接S_IFREG 0100000     一般文件S_IFBLK 0060000     區塊裝置S_IFDIR 0040000     目錄S_IFCHR 0020000     字符裝置S_IFIFO 0010000     先進先出S_ISUID 04000     文件的(set user-id on execution)位S_ISGID 02000     文件的(set group-id on execution)位S_ISVTX 01000     文件的sticky位S_IRUSR(S_IREAD) 00400     文件所有者具可讀取權限S_IWUSR(S_IWRITE)00200     文件所有者具可寫入權限S_IXUSR(S_IEXEC) 00100     文件所有者具可執行權限S_IRGRP 00040             用戶組具可讀取權限S_IWGRP 00020             用戶組具可寫入權限S_IXGRP 00010             用戶組具可執行權限S_IROTH 00004             其他用戶具可讀取權限S_IWOTH 00002             其他用戶具可寫入權限S_IXOTH 00001             其他用戶具可執行權限 

上述的文件類型在POSIX中定義了檢查這些類型的宏定義:

    S_ISLNK (st_mode)    判斷是否為符號連接S_ISREG (st_mode)    是否為一般文件S_ISDIR (st_mode)    是否為目錄S_ISCHR (st_mode)    是否為字符裝置文件S_ISBLK (s3e)        是否為先進先出S_ISSOCK (st_mode)   是否為socket

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

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

相關文章

關于objective-c的一點隨筆

多日混跡cocoachina&#xff0c;這篇隨筆算是積累點前人經驗吧。 首先&#xff0c;要多逛兩個很好的網站&#xff0c;Stack Overflow和github. 對于新人&#xff0c;一定要注意良好的格式和命名&#xff0c;不然對于日后回頭看代碼會非常難&#xff0c;oc不限制變量名稱和函數名…

【轉載】Ubuntu環境下配置Android Studio

之前學習Android開發的時候&#xff0c;一直跟各種教程一樣&#xff0c;使用的是EclipseADT&#xff0c;主要是比較方便&#xff0c;容易上手&#xff0c;特別是對于習慣用Eclipse開發java的朋友來說&#xff0c;上手更是好無壓力。但畢竟EclipseADT最多只能算Google的干兒子&a…

linux怎么進去vi編輯器,red hat enterprise linux開機怎么進入vi編輯器界面?

2015-05-21 回答后面輸入直接打回車就會顯示出來如下xx文件#■sa■jsadjk#■sa■jsklfjdl kl■sa&#xff1a;----現在是低行模式 現在按esc 進入第一個模式(命令模式)就變成下面xx文件#dsadjsadjk#dsadjsklfjdl kldsa現在我們按個v 就進入可是模式 現在我們一個移動光標選擇要…

數據結構--鏈式線性表

環境&#xff1a;dev c #include<stdio.h> #include<stdlib.h>typedef struct LNode *List; typedef int ElementType;struct LNode{ElementType Data;List next; };int Length(List Ptrl); List FindKth(int k,List Ptrl); List Find(ElementType x,List Ptrl); …

linux査 到漠河 裝apache,如何在Ubuntu上搭建一臺安全的Apache?Web服務器

滿意答案1.安裝Apache2使用下面這個命令&#xff0c;安裝Apache2及其他庫。1$ sudo apt-get -y install apt-get install apache2 apache2.2-common apache2-doc apache2-mpm-prefork apache2-utils libexpat1 ssl-cert libapache2-mod-php5 php5 php5-common php5-gd php5-cli…

vs2010 中添加 ActiveX Control Test Container工具

vs2010中的TSTCON( ActiveX Control Test Container )工具非自動安裝&#xff0c;而是作為一個例程提供。所以應找到該例程&#xff0c;并編譯&#xff1a; 如vs2010安裝在默認路徑則 1, 進入&#xff1a;C:\Program Files\Microsoft Visual Studio 10.0\Samples\1033&#xff…

linux c實現mypwd

這個其實很簡單&#xff0c;只需要調用getcwd()這個函數就行了。 char *getcwd(char *buffer,int maxlen); 功能&#xff1a;獲取當前工作目錄 參數&#xff1a;buffer指向用來存儲絕對路徑的數組&#xff0c;maxlen絕對路徑的字符大小 返回&#xff1a;成功則返回當前的工作目…

安裝Discuz

1.下載Discuz 版本文件http://download.comsenz.com/DiscuzX/3.2/Discuz_X3.2_SC_GBK.zip2.下載PHPhttp://windows.php.net/downloads/releases/php-5.6.9-Win32-VC11-x64.zip把里面文件的php.ini-development 更名為php.ini Uncomment下列語句 extension_dir "ext"…

linux跑caffe模型的步驟,Caffe初步實踐——使用訓練好的模型完成語義分割任務

Caffe剛剛安裝配置結束&#xff0c;乘熱打鐵&#xff01;(一)環境準備前面我有兩篇文章寫到caffe的搭建&#xff0c;第一篇cpu only &#xff0c;第二篇是在服務器上搭建的&#xff0c;其中第二篇因為硬件環境更佳我們的步驟稍顯復雜。其實&#xff0c;第二篇也僅僅是caffe的初…

關于 Code First

第一感覺還是很新鮮的&#xff0c;你可以自由的控制數據結構。 比如&#xff0c;你想象oracle那樣&#xff0c;給每個表增加4個字段&#xff0c;創建人&#xff0c;創建時間&#xff0c;更新人&#xff0c;更新時間。完全可以創建一個父類包含著四個屬性&#xff08;甚至可以把…

靈悟禮品網上專賣店——新建數據庫

一、小組成員&#xff1a; 洪雪意&#xff08;產品負責人&#xff09; 陳淑筠&#xff08;Master&#xff09; 二、組內人員任務情況 計劃完成的任務的第三個模塊&#xff1a;分析并建立數據庫 已完成的任務&#xff1a; 任務的第三個模塊&#xff1a; 陳淑筠&#xff08;負責…

操作系統上機題目(多進程1)

1、創建1個子進程2、程通過管道與子進程連接 子進程的標準輸出連接到管道的寫端主進程的標準輸入連接到管道的讀端3、進程中調用exec(“echo”, “echo”, “hello world”, NULL)4、進程中調用read(0, buf, sizeof(buf))&#xff0c;從標準輸入中獲取子進程發送的字符串&…

Oracle數據庫dmp文件Dos命令下導入導出

Oracle數據庫dmp文件Dos命令下導入導出 2013-03-09 18:22:52| 分類&#xff1a; Oracle |舉報|字號 訂閱 數據導出: 一. 導出工具exp 他是操作系統下一個可執行的文件,存放目錄/Oracle_Home/bin. exp導出工具將數據庫中數據備份壓縮成一個二進制系統文件,可以在不同的OS間遷…

c語言報錯找不到標識符,error C3861: “_T”: 找不到標識符

頭天好好的程序&#xff0c;第二天一早就報錯&#xff0c;還是莫名其妙的錯誤&#xff1a;atlconv.h等頭文件中的“_T” 報錯&#xff0c;百思不得其解&#xff0c;各種搜索而不得&#xff0c;整個人都崩潰了。出問題一定是有原因的&#xff0c;后來冷靜下來&#xff0c;縷縷思…

js 面向對象插件寫法,還是很好理解的

/** * Created by jiangtao on 2015/5/12. * name jihe */(function () { function gather(msg) { //適應參數 if (msg) { if (msg.imgFile ! undefined) { this.imgFile msg.imgFile; }; if (msg.wechatAppid ! undefined) { this.wechatAppid msg.wechatAppid; }; }; this.…

操作系統上機題目(多進程2)

1、主進程創建2個子進程&#xff0c;主進程通過兩個管道分別與兩個子進程連接2、第一個子進程計算從1加到50的和&#xff0c;并將結果通過管道送給父進程3、第一個子進程計算從50加到100的和&#xff0c;并將結果通過管道送給父進程4、父進程讀取兩個子進程的結果&#xff0c;將…

JavaScript 的簡介

JavaScript 是一種基于對象和事件驅動的腳本語言。JavaScript和HTML一起實現網頁與客戶端的交互&#xff0c;從而可以開發客戶端的應用程序。JavaScript是通過潛入在標準的HTML文件中實現的&#xff0c;可以直接控制瀏覽器窗口個元素以及頁面內容。JavaScript一個重要的功能就是…

c語言大樂透編譯,Excel大樂透搖號vba代碼分享,說不定就中百萬了呢

大家好我是Excel從零到一&#xff0c;今天閑來無聊做了一套大樂透搖號程序的vba代碼分享給大家來看下效果Excel大樂透搖號vba代碼分享&#xff0c;說不定就中百萬了呢Sub 搖號()Dim i, a, test, s(1 To 35) As IntegerFor i 1 To 5line1: test Application.WorksheetFunction…

操作系統上機題目(多線程1)

主線程創建10個子線程 第0個子線程計算從01加到10的和 - 第1個子線程計算從11加到20的和 … 第9個子線程計算從91加到100的和 2. 主線程歸并10個子線程的計算結果&#xff0c;最終結果為5050 本題必須使用線程參數來完成 #include<stdio.h> #include<unistd.h> #i…

紙上談兵: 堆 (heap)

紙上談兵: 堆 (heap) 作者&#xff1a;Vamei 出處&#xff1a;http://www.cnblogs.com/vamei 歡迎轉載&#xff0c;也請保留這段聲明。謝謝&#xff01; 堆(heap)又被為優先隊列(priority queue)。盡管名為優先隊列&#xff0c;但堆并不是隊列。回憶一下&#xff0c;在隊列中&a…