Linux的系統呼叫open,write,read,close,及相關總結
在進行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);
- 1
- 2
- 3
- 4
- 5
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);
- 1
- 2
- 3
- 4
fd:檔案描述符
buf:寫入的緩衝區
count:寫的字元長度,也就是看你需要寫多少
read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
- 1
- 2
- 3
- 4
read的引數和write的引數很相像,只有第二個引數的含義有些不一樣,它的buf是需要讀的緩衝區
close
#include <unistd.h>
int close(int fd);
- 1
- 2
- 3
- 4
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,我們就不得不來區分下FILE和fd
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的封裝
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
可以看到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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
執行結果:
[[email protected] test]$ ./hello
hello printf
hello fwrite
hello write
但當我們對程序實現輸出重定向,你就會發現詭異的事情:
[[email protected] test]$ ./hello > file
[[email protected] 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下標所指向的內容
- 追加重定向(>>) 後面多一個追加選項
相關推薦
系統呼叫——open、write、read和close
一、檔案描述符 每一個程序都有一個與之相關的檔案描述符,它們是一些小值整數,我們可以通過這些檔案描述符來訪問開啟的檔案。 一般地,一個程式開始執行時,會自動開啟3個檔案描述符: 0——–標準輸入———-stdin 1——–標準輸出———-stdout
linux系統呼叫open、write、close、read以及stat函式詳解
學習筆記 參考連結1 、參考連結2以及百度百科 在進行C語言學習的時候我們瞭解到了C語言相關的一些IO操作,如fopen,fwrite,fread,fprintf,fclose等相關函式,他們都是由C庫函式提供的一些函式,是將作業系
linux 系統呼叫open 七日遊(二)
接著昨日的旅程,我們應該開始處理具體的子路徑了: 【fs/namei.c】 sys_open->do_sys_open->do_filp_open->path_openat->link_path_walk 點選(此處)摺疊或開啟 &n
linux系統呼叫open七日遊(一)
友情提示:您需要一個 kernel 3.15.6,下載地址: https://www.kernel.org/pub/linux/kernel/v3.0/linux-3.15.6.tar.xz 我們將以 Linux 系統呼叫 open 為主線,參
Linux 系統呼叫 open 七日遊(七)
【場景三】open(pathname, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR) 在這個場景中我們希望建立一個新檔案(O_CREAT),並賦予該檔案使用者可讀(S_IRUSR)和使用者可寫(S_IW
Linux的系統呼叫open,write,read,close,及相關總結
在進行C語言學習的時候我們瞭解到了C語言相關的一些IO操作,如fopen,fwrite,fread,fprintf,fclose等相關函式,他們都是由C庫函式提供的一些函式,是將作業系統的系統呼叫加以封裝,雖說Linux是由C語言實現的,但為了使我們更加的瞭解Linux,就需
組合語言呼叫Linux系統呼叫read和write
.section .data UserMsg: .ascii "Please input the message:" LenOfUserMsg: .equ lenMsg, LenOfUserMsg - UserMsg #.section .bss # .lcomm r
linux系統網卡配置文件找不到,DHCP不工作情況解決
linux今天,我發現了這樣一個情況,那就是網卡配置文件少了一個/etc/init.d/network status ,看到網絡配置少了一個如何做呢?將其他的網卡配置文件復制一份,進入到/etc/sysconfig/network-scripts下,進行copthoyfor instance,cp ifcfg
Linux系統中用腳本安裝虛擬機及其管理,快照及虛擬機重置
linux---腳本安裝 快照 想要快速安裝多臺虛擬機,可以對原有虛擬機硬盤文件做一個快照,使用快找安裝多個虛擬速度是相當快的,那麽接下來我將介紹如何創建快照以及編寫簡單的shell命令安裝虛擬機的方法。一、安裝虛擬機(1)用shell腳本安裝(2)得到一個虛擬機的全端管理及硬盤文件(3)創建虛擬機快
Linux 檔案系統呼叫open七日遊(三)
接著上回,當對“.”和“..”處理完成後就直接返回進入下一個子路徑迴圈了,但如果當前子路徑不是“.”或“..”呢? 【fs/namei.c】 sys_open > do_sys_open > do_filp_open >&
Linux檔案系統呼叫open 七日遊 (六)
還記得在上一個場景中,build_open_flags裡面有一個對標誌位O_PATH的判斷麼?現在我們就來看看這個標誌位是幹啥的: 【場景二】open(pathname,O_PATH) 這個O_PATH似乎是不常用的,咱們先看看它的使用
linux檔案系統呼叫 open 七日遊(四)
現在,我們的“路徑行走”只剩下最後一個小問題需要處理了——符號連結。 【fs/namei.c】 sys_open > do_sys_open > do_filp_open > path_openat &g
Linux系統--CentOS7下Mysql(docker)映象建立,使用者,表以及資料初始化
1.docker下載(環境為centos7)yum install docker-engine2.下載完成後啟動docker使用命令:service docker start3.為docker下載映象提速curl -sSL https://get.daocloud.io/da
delphi中,write和read的用法?什麼時候需要用?
如你所說,在控制元件或者類的屬性中,read 表示 讀取,write 則表示設定。比如在類中:TTestClass = (Class)privateFOrderCode:String;publicproperty OrderCode:String read FOrderCode write FOrd
linux系統應用層基礎面試題目(很完整,暫時沒看)
1. 下面的網路協議中,面向連線的的協議是: A 。 A 傳輸控制協議 B 使用者資料報協議 C 網際協議 D 網際控制報文協議 2. 在/etc/fstab檔案中指定的檔案系統載入引數中, D 引數一般用於CD-ROM等移動裝置。 A defaults B sw C rw和ro D noauto 3. Li
Linux系統中/dev/mtd與/dev/mtdblock的區別,即MTD字元裝置和塊裝置的區別
1. /dev/mtdN 是Linux 中的MTD架構中,系統自己實現的mtd分割槽所對應的字元裝置,其裡面添加了一些ioctl,支援很多命令,如MEMGETINFO,MEMERASE等。 而mtd-util中的flash_eraseall等工具,就是以這些ioctl為基礎而
Linux系統下安裝三個或者多個tomcat ,步驟詳細。
即然安裝多個tomcat,那麼必然建立在系統已經安裝好了jdk,並且會安裝一個tomcat的基礎上,這裡就不做過多描述,直奔主題。安裝多個tocat的方式其實和安裝一個大同小異,只是需要更改一些配置。先
arm linux 系統呼叫過程
在Linux下系統呼叫是用軟中斷實現的,下面以一個簡單的open例子簡要分析一下應用層的open是如何呼叫到核心中的sys_open的。 t8.c 1: #include <stdio.h> 2: #include <sys/types.h> 3:
一次性講明白Linux系統呼叫(1)
什麼是系統呼叫 Linux核心中設定了很多可以實現各種系統功能的子程式,這些子程式就叫系統呼叫。而系統呼叫和普通函式呼叫的區別主要是在系統呼叫是系統提供的,函式一般是函式庫或者自己提供的。 為什麼要用系統呼叫 其實很多我們平時用的C語言標準函式,在Linux
linux 系統呼叫 inotify & epoll
一、inotify 作用: 監控一個目錄下檔案的增加、刪除事件 1.重要的資料結構 // 發生的event結構 struct inotify_event { __s32 wd; &nb