系統調用 系統調用: 操作系統提供給用戶程式調用的一組“特殊”介面,用戶程式可以通過這組“特殊”介面來獲得操作系統內核提供的服務 為什麼用戶程式不能直接訪問系統內核提供的服務為了更好地保護內核空間,將程式的運行空間分為 內核空間 和 用戶空間(也就是常稱的內核態和用戶態),它們分別運行在不同的級別上 ...
系統調用
系統調用: 操作系統提供給用戶程式調用的一組“特殊”介面,用戶程式可以通過這組“特殊”介面來獲得操作系統內核提供的服務
為什麼用戶程式不能直接訪問系統內核提供的服務為了更好地保護內核空間,將程式的運行空間分為 內核空間 和 用戶空間(也就是常稱的內核態和用戶態),它們分別運行在不同的級別上 在邏輯上是相互隔離的 。 因此 用戶進程在通常情況下不允許訪問內核數據 ,也無法使用內核函數,它們只能在用戶空間操作用戶數據 ,調用用戶空間的函數 。
進行系統調用時 ,程式運行空間從用戶空間進入內核空間 ,處理完後再返回到用戶空間系統調用並不是直接與程式員進行交互的,它僅僅是一個通過軟中斷機制向內核提交請求,以獲取內核服務的介面 。在實際使用中程式員調用的通常是用戶編程介面 API 。
Linux 中的系統調用包含在 Linux 的 libc 庫中,通過標準的 C 函數調用方法可以調用系統命令相對 API 更高了一層,它實際上是一個可執行程式,它的內部調用了用戶編程介面 (API )來實現相應的功能 。內核如何區分和引用特定的文件
通過文件描述符 。文件描述符是一個非負的整數 ,是一個索引值 ,指向在內核中每個進程打開文件的記錄表 。 當打開一個現存文件或創建一個新文件時,內核就向進程返回一個文件描
述符;當需要讀寫文件時 也需要把文件描述符作為參數傳遞給相應的函數 。是一個非負的整數(通常是小整數),posix標準要求每次打開一個文件,必須使用當前進程最小的文件描述符號碼,因此打開一定是3.
一個進程啟動時 通常會打開 3 個文件:
標準輸入 | 標準輸入 | 標準出錯 |
---|---|---|
STDIN_FILENO | STDOUT_FILENO | STDERR_FILENO |
stdin | stdout | stderr |
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define MSG_STR "hello world\n"
int main(int argc, char **argv)
{
printf("%s",MSG_STR);
fputs(MSG_STR,stdout);
write(STDOUT_FILENO,MSG_STR,strlen(MSG_STR));//標準輸出到屏幕MSG_STR
return 0;
}
關於fputs和weitey
fputs(const char *s, FILE *stream);
write(int fd, const void *buf, size_t count);
文件的創建/打開
open() 函數用於打開或者創建文件。其在打開或者創建文件時可以指定文件的屬性及用戶的許可權等各種參數。
int open(const char *pathname, int flags);//打開已存在的文件
int open(const char *pathname, int flags, mode_t mode);//打開不存在的文件
//flags:read write操作文件的許可權
//mode:該文件在磁碟中 相對於 用戶的許可權
int open(const char *path, int oflag, [mode_t mode]);
args:
const char *path: 文件路徑,可以是絕對,也可以是相對路徑
int oflag : 文件打開的方式
- O_RDONLY 只讀打開
- O_WRONLY 只寫打開
- O_RDWR 可讀可寫打開
以上3種必選一個,以下4種可以任意選擇
- O_APPEND 追加打開,所寫數據附加到文件末
- O_CREAT 若此文件不存在則創建它
- O_EXCL 若文件存在則報錯返回
- O_TRUNC 如果文件已存在,並且以只寫或可讀可寫方式打開
則將其長度截斷為0位元組
[mode_t mode] : 文件許可權,只有在創建文件時需要使用
return:
文件描述符,非負整數是成功,-1是失敗
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc ,char **argv)
{
int fd = -1;
if((fd = open("test.txt",O_CREAT|O_RDWR,0666))<0)
if(-1==fd)
{
printf("文件創建失敗\n");
}
else
{
printf("文件打開成功,fd = %d\n",fd);
}
return 0;
}
寫文件
當文件打開後,我們就可以向該文件寫數據了。在Linux系統中,用 write() 向打開的文件寫入數據,要使用這個函數,需要包含 #include <unistd.h> 。下麵是函數的說明:
ssize_t write(int fildes, const void *buf, size_t nbyte);
args:
int fildes : 寫入文件的文件描述符
const void *buf: 寫入數據在記憶體空間存儲的地址
size_t nbyte : 期待寫入數據的最大位元組數
return:
文件實際寫入的位元組數,非負整數是成功,-1是失敗(磁碟已滿或者超出該文件的長度等)
if((rv = write(fd, MSG_STR,strlen(MSG_STR)))<0)
if(rv == -1)
{
printf("寫入數據失敗\n");
}
else
{
printf("寫入數據成功\n");
}
讀文件
同寫文件類似,要使用讀文件函數 read() ,需要包含 #include <unistd.h> 。下麵是函數的說明:
ssize_t read(int fildes, void *buf, size_t nbyte);
args:
int fildes : 讀取文件的文件描述符
void *buf : 讀取數據在記憶體空間存儲的地址
size_t nbyte: 期待讀取數據的最大位元組數
return:
文件實際讀取的位元組數,非負整數是成功,-1是失敗
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFSIZE 1024
#define MSG_STR "i love linux\n"
int main(int argc ,char **argv)
{
int fd = -1;
int rv = -1;
char buf[BUFSIZE];
if((fd = open("test.txt",O_CREAT|O_RDWR,0666))<0)
if(fd==-1)
{
printf("文件創建失敗\n");
}
else
{
printf("文件打開成功,fd = %d\n",fd);
}
if((rv = write(fd, MSG_STR,strlen(MSG_STR)))<0)
if(rv == -1)
{
printf("寫入數據失敗\n");
}
else
{
printf("寫入數據成功\n");
}
memset(buf,0,sizeof(buf));//把buf的值為0,
if((rv = read(fd,buf,sizeof(buf)))<0)
if(rv == -1)
{
printf("讀寫失敗\n");
}
else
{
printf("讀寫成功\n");
goto cleanup;
}
printf("讀寫的數據 %d\n %s\n",rv,buf);
return 0;
}
但是這樣讀出是空的,所以要使用lseek文件偏離量,通俗來說:就是改變游標的位置,從哪裡讀數據.
memset函數
memset是電腦中C/C++語言初始化函數。作用是將某一塊記憶體中的內容全部設置為指定的值, 這個函數通常為新申請的記憶體做初始化工作。
void *memset(void *s, int ch, size_t n);
str -- 指向要填充的記憶體塊。
c -- 要被設置的值。該值以 int 形式傳遞,但是函數在填充記憶體塊時是使用該值的無符號字元形式。
n -- 要被設置為該值的字元數。
文件的偏移量
在每個打開的文件中都有一個文件的偏移量,文件的偏移量會根據文件的讀寫而改變位置。我們可以通過 lseek() 函數來調整文件的偏移量。預設情況下,新打開文件的文件偏移量在文件的開始。同 write() 和 read() 函數類似,要使用這個函數,需要包含 #include <unistd.h> 。下麵是函數的說明:
off_t lseek(int fildes, off_t offset, int whence);
args:
int fildes : 修改文件的文件描述符
off_t offset: 文件偏移量移動的距離
int whence : 文件偏移量的基址
- SEEK_SET 文件開始處
- SEEK_CUR 文件當前位置
- SEEK_END 文件結束處
return:
當前文件指針的位置,非負整數是成功,-1是失敗
lseek(fd , 0 ,SEEK_SET);//將文件偏移量設置到文件開始第一個位元組上
lseek(fd , -1 ,SEEK_END);//將文件偏移量設置在文件倒數第一個位元組上
在數據寫入成功後,把文件偏移量移到文件開始第一行位元組上
if((rv = write(fd, MSG_STR,strlen(MSG_STR)))<0)
if(rv == -1)
{
printf("寫入失敗\n");
}
else
{
printf("寫入數據成功\n");
goto cleanup;
}
lseek(fd,0,SEEK_SET);
關閉文件
當文件不再被使用時,可以調用 close() 函數來關閉被打開的文件。 除了用 close() 顯示地關閉文件外,通過結束進程也能隱式地關閉被該進程打開的所有文件。要使用該函數,需要包含 #include <unistd.h> 。下麵是函數的說明:
int close(int fildes);
args:
int fildes: 要關閉文件的文件描述符
return:
文件關閉狀態,0是成功,-1是失敗
代碼實現
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFSIZE 1024
#define MSG_STR "i love linux\n"
int main(int argc ,char **argv)
{
int fd = -1;
int rv = -1;
char buf[BUFSIZE];
if((fd = open("test.txt",O_CREAT|O_RDWR,0666))<0)
if(fd==-1)
{
printf("文件創建失敗\n");
goto cleanup;
}
else
{
printf("文件打開成功,fd = %d\n",fd);
}
if((rv = write(fd, MSG_STR,strlen(MSG_STR)))<0)
if(rv == -1)
{
printf("寫入數據失敗\n");
goto cleanup;
}
else
{
printf("寫入數據成功\n");
}
lseek(fd,0,SEEK_SET);
memset(buf,0,sizeof(buf));
if((rv = read(fd,buf,sizeof(buf)))<0)
if(rv == -1)
{
printf("讀寫失敗\n");
goto cleanup;
}
else
{
printf("讀寫成功\n");
}
printf("讀寫的數據 %d\n %s\n",rv,buf);
cleanup:
close(fd);
return 0;
}
strerror函數
C 庫函數 char *strerror(int errnum) 從內部數組中搜索錯誤號 errnum,並返回一個指向錯誤消息字元串的指針。strerror 生成的錯誤字元串取決於開發平臺和編譯器。
char *strerror(int errnum)
進一步代碼實現
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#define BUFSIZE 1024
#define MSG_STR "hello world\n"
int main(int argc ,char **argv)
{
int fd = -1;
int rv = -1;
char buf[BUFSIZE];
fd = open("test.txt",O_RDWR|O_CREAT|O_TRUNC,0666);
if(fd < 0)
{
perror("創建/打開文件失敗");
return 0;
}
printf("打開文件成功 [%d]\n",fd);
if((rv = write(fd,MSG_STR,strlen(MSG_STR))) < 0)
{
printf("文件寫入失敗:%s\n",strerror(errno));
goto cleanup;
}
lseek(fd, 0 ,SEEK_SET);
memset(buf, 0 ,sizeof(buf));
if((rv = read(fd,buf,sizeof(buf))) < 0)
{
printf("讀文件失敗:%s\n",strerror(errno));
goto cleanup;
}
printf("從文件讀出%d數據:%s\n",rv,buf);
cleanup:
close(fd);
return 0;
}