linux PCB数组,Linux中的系统IO函数
一、整體大綱
二、 系統(tǒng)IO函數(shù)
1. 一些概念
文件描述符
PCB
C庫(kù)函的IO緩沖區(qū)
1)?文件描述符
int 類型
一個(gè)進(jìn)程最多可打開多少文件
2)?pcb
進(jìn)程控制塊
在其中有一個(gè)文件描述符表 -- 數(shù)組[1024]
C庫(kù)IO函數(shù)工作流程:
pcb和文件描述符:
2. 虛擬地址空間
虛擬地址空間就是程序啟動(dòng)起來之后從硬盤上會(huì)有一塊虛擬內(nèi)存分配出來。
cpu 為什么要使用虛擬地址空間與物理地址空間映射?解決了什么樣的問題?
1)方便編譯器和操作系統(tǒng)安排程序的地址分布。
程序可以使用一系列相鄰的虛擬地址來訪問物理內(nèi)存中不相鄰的大內(nèi)存緩沖區(qū)。通過虛擬地址空間與物理地址空間映射解決不連續(xù)的緩沖區(qū)的問題。
2)方便進(jìn)程之間隔離
不同進(jìn)程使用的虛擬地址彼此隔離。一個(gè)進(jìn)程中的代碼無法更改正在由另一進(jìn)程使用的物理內(nèi)存。
3)方便OS使用你那可憐的內(nèi)存。
程序可以使用一系列虛擬地址來訪問大于可用物理內(nèi)存的內(nèi)存緩沖區(qū)。當(dāng)物理內(nèi)存的供應(yīng)量變小時(shí),
內(nèi)存管理器會(huì)將物理內(nèi)存頁(yè)(通常大小為 4 KB)保存到磁盤文件。數(shù)據(jù)或代碼頁(yè)會(huì)根據(jù)需要在物理內(nèi)存與磁盤之間移動(dòng)。
虛擬地址空間的布局如下:
0-3G是用戶空間? ? ? ? 3-4G是內(nèi)核空間
用戶區(qū)? ? ? ? ? ? ? ? ? ? ? ? 內(nèi)核區(qū)
代碼段
已經(jīng)初始化的全局變量
未被初始化的全局變量
堆 -- 從下往上
共享庫(kù)
棧 - 從上往下
環(huán)境變量
內(nèi)核區(qū)
3. C庫(kù)函數(shù)與系統(tǒng)函數(shù)的關(guān)系
FD:文件描述符 FP_POS:文件指針 BUFFER:緩沖區(qū)
write對(duì)0-3G的用戶空間進(jìn)行操作 sys_write()對(duì)3-4G的內(nèi)核空間進(jìn)行操作
4. IO函數(shù)介紹
1)open
查看 man 2 open
頭文件:
#include #include#include
函數(shù)原型:
int open(const char *pathname, intflags);int open(const char *pathname, int flags, mode_t mode);
參數(shù)說明
pathname 文件名
flags
必選項(xiàng):
O_RDONLY 只讀
O_WRONLY 只寫
O_RDWR 讀寫
可選項(xiàng):
O_APPEND 追加
O_CREAT 創(chuàng)建文件
O_EXCL和O_CREATE一起使用,如果文件存在則報(bào)錯(cuò)
O_NONBLOCK 非阻塞
Mode 權(quán)限位,最終(mode&~umask)
返回值:
成功:返回最小的可用文件描述符
失敗:返回-1,并且設(shè)置errno
open函數(shù)中的errno:
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 if (argc != 2)10 {11 printf("./a.out filename\n")12 return -1
13 }14 int fd = open(argv[1], O_CREAT|O_TRUNC|O_WRONLY, 0666);15 close(fd);16
17 return 0;18 }
使用open實(shí)現(xiàn)一個(gè)touch功能
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7
8 int main(int argc, char *argv[])9 {10 int num = 3;11 char filename[128] = {0};12 while(1)13 {14 sprintf(filename, "temp_%04d", num++);15 if (open(filename, O_RDONLY|O_CREAT, 0666) < 0)16 {17 perror("open err:");18 break;19 }20 }21 printf("num == %d\n", num);22
23 return 0;24 }
一個(gè)進(jìn)程打開的最大文件數(shù)(1024)
2)close
作用:關(guān)閉文件描述符
頭文件:
#include
函數(shù)原型:
int close(int fd);
參數(shù)說明:
fd文件描述符
返回值:
成功:返回0
失敗:返回-1,并且設(shè)置errno
3)read讀
頭文件
#include
函數(shù)原型
ssize_t read(int fd, void *buf, size_t count);
參數(shù)說明
fd 文件描述符
buf緩沖區(qū)
count緩沖區(qū)大小
返回值
失敗:返回-1,設(shè)置errno
成功:返回讀到的字節(jié)數(shù)
0代表讀到文件末尾
非阻塞的情況下read返回-1,但是此時(shí)需要判斷error的值。
4)write寫
頭文件
#include
函數(shù)原型
ssize_t write(int fd, const void *buf, size_t count);
參數(shù)說明:
fd文件描述符
buf緩沖區(qū)
count緩沖區(qū)大小
返回值
失敗:返回-1,設(shè)置errno
成功:返回寫入的字節(jié)數(shù)
0代表未寫入
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 if (argc != 2)10 {11 printf("./a.out filename\n")12 return -1
13 }14 int fd = open(argv[1], O_RDONLY);15 char buf[256] = {0};16 int ret = 0;17 while ((ret = read(fd, buf, ziseof(buf))) != 0)18 {19 if (ret == -1)20 {21 perror("read err:");22 return -1;23 }24 else
25 {26 write(STDOUT_FILENO, buf, ret);27 }28 }29
30 close(fd);31
32 return 0;33 }
實(shí)現(xiàn)一個(gè)cat功能
需求:給一個(gè)文件中寫入內(nèi)容,寫完之后打開該文件再讀取寫入的內(nèi)容?
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 if (argc != 2)10 {11 printf("./a.out filename\n");12 return -1;13 }14 int fd = open(argv[1], O_RDWR|O_CREAT, 0666);15
16 char data[12] = "hello world";17 write(fd, data, sizeof(data));18
19 char buf[256] = {0};20 int ret = 0;21 while ((ret = read(fd, buf, sizeof(buf))) != 0)22 {23 if (ret == -1)24 {25 perror("read err:");26 return -1;27 }28 else
29 {30 write(STDOUT_FILENO, buf, ret); //STDIN_FILENO, STDERR_FILENO
31 }32 }33
34 close(fd);35
36 return 0;37 }
bug版本
結(jié)果:內(nèi)容寫入到文件中,但是并未按預(yù)期輸出到屏幕上。
原因:是由于write完成之后,fd到了文件末尾,因此read時(shí)到了文件末尾,無法讀取文件數(shù)據(jù)
解決方法:寫完之后將文件指針設(shè)置到文件開頭,使用請(qǐng)看下文要介紹的lseek函數(shù)。
5)lseek寫
頭文件
#include #include
函數(shù)原型
off_t lseek(int fd, off_t offset, int whence);
參數(shù)說明
fd文件描述符
offset偏移量
whence:
SEEK_SET 文件開始位置
SEEK_CUR 文件當(dāng)前位置
SEEK_END 文件結(jié)尾
返回值
失敗:返回-1,設(shè)置errno
成功:返回當(dāng)前位置到文件開頭的長(zhǎng)度
lseek作用
移動(dòng)文件讀寫位置
計(jì)算文件大小
拓展文件
示例:
a.?移動(dòng)文件讀寫位置
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 if (argc != 2)10 {11 printf("./a.out filename\n");12 return -1;13 }14 int fd = open(argv[1], O_RDWR|O_CREAT, 0666);15
16 char data[12] = "hello world";17 write(fd, data, sizeof(data));18 //文件讀寫位置此時(shí)在末尾19 //需要移動(dòng)讀寫位置
20 lseek(fd, 0, SEEK_SET); //將fd移動(dòng)到文件頭
21
22 char buf[256] = {0};23 int ret = 0;24 while ((ret = read(fd, buf, sizeof(buf))) != 0)25 {26 if (ret == -1)27 {28 perror("read err:");29 return -1;30 }31 else
32 {33 write(STDOUT_FILENO, buf, ret); //STDIN_FILENO, STDERR_FILENO
34 }35 }36
37 close(fd);38
39 return 0;40 }
修改上例的bug(寫入文件內(nèi)容并讀取文件內(nèi)容打印到屏幕)
b.?計(jì)算文件大小
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 if (argc != 2)10 {11 printf("./a.out filename\n");12 return -1;13 }14 int fd = open(argv[1], O_RDONLY);15
16 int ret = lseek(fd, 0, SEEK_END); //將fd移動(dòng)到文件頭
17 printf("file size is %d\n", ret); //注意實(shí)際讀到的文件大小為ret-1
18
19 close(fd);20
21 return 0;22 }
計(jì)算文件大小(輸出文件字節(jié)數(shù))
c.?拓展文件
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 if (argc != 2)10 {11 printf("./a.out filename\n");12 return -1;13 }14 int fd = open(argv[1], O_WRONLY|O_CREAT, 0666);15 //拓展文件
16 int ret = lseek(fd, 1024, SEEK_END); //將fd移動(dòng)到文件頭17 //需要至少寫一次,否則不能保存
18 write(fd, "a", 1);19 printf("file size is %d\n", ret);20
21 close(fd);22
23 return 0;24 }
拓展文件
阻塞的概念:
read函數(shù)在讀設(shè)備或者讀管道,或者讀網(wǎng)絡(luò)的時(shí)候。
輸入輸出設(shè)備對(duì)應(yīng)的/dev/tty。
6)fcntl
頭文件
#include #include
函數(shù)原型
int fcntl(int fd, int cmd, ... /*arg*/ );
參數(shù)說明:
fd文件描述符
cmd 命令
返回值
不同的cmd返回值不同
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 int main(int argc, char *argv[])8 {9 //O_NONBLOCK設(shè)置為非阻塞
10 int fd = open("/dev/tty", O_RDWR);11 //fcntl()函數(shù),設(shè)置非阻塞
12 int flags =fcntl(fd, F_GETFL);13 flags |=O_NONBLOCK;14 fcntl(fd, F_SETFL, flags);15
16 char buf[256] = {0};17 int ret = 0;18 while(1)19 {20 //如果沒有設(shè)置O_NONBLOCK
21 ret = read(fd, buf, sizeof(buf));22 if (ret < 0)23 {24 perror("read err:");25 printf("ret is %d\n", ret);26 }27
28 if(ret)29 {30 printf("buf is %s\n", buf);31 }32 printf("haha\n");33 sleep(1);34 }35 close(fd);36
37 return 0;38 }
使用fcntl函數(shù)實(shí)現(xiàn)讀非阻塞
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的linux PCB数组,Linux中的系统IO函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux中分区乱了,找到了linux分
- 下一篇: 老板电器是上市公司吗