Linux kernel: process management - IO operation management

Using Linux's file API, we often see a thing called a file descriptor.

What is a file descriptor?

(1) The file descriptor is actually a number. This number represents a specific meaning in a process. When we open a file, the operating system constructs some data structures in memory to represent the dynamic file, and then returns Give the application a number as a file descriptor, and this number is bound to the data structures that maintain this dynamic file in our memory. If our application wants to operate this dynamic file in the future, we only need to use this file descriptor Make a distinction.

(2) The file descriptor is used to distinguish multiple files opened by a program.

(3) The scope of the file descriptor is the current process, and the file descriptor of the current process is meaningless

(4) The legal range of the file descriptor fd is 0 or a positive number, and cannot be a negative number

(5) The fd returned by open must be recorded well. All future operations to this file must rely on this fd to correspond to this file. When closing the file at last, fd is also required to specify to close this file. If the fd is lost before we close the file, then the file cannot be closed or read or written.

1) Open and read files

1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 
 7 int main(int argc, char const *argv[]) {
 8 
 9     int fd = -1; //文件描述符
10 
11     //打开文件
12     fd = open( "ghostwu.txt", O_RDWR );
13 
14     if ( -1 == fd ) {
15         printf("文件打开失败\n");
16     }else {
17         printf("文件打开成功,fd=%d\n", fd );
18     }
19 
20     //读取文件
21     int count = 0;
22     char buf[20];
23     count = read( fd, buf, 50 );
24     if ( -1 == count ) {
25         printf("文件读取失败\n");
26     }else {
27         printf("文件读取成功,实际读取的字节数目为:%d\n内容为%s\n", count, buf );
28     }
29 
30     //关闭文件
31     close( fd );
32 
33     return 0;
34 }

The ghostwu.txt file needs to exist in the current directory, otherwise it will fail when opening, and 2 APIs are involved here

int open(const char *pathname, int flags);

open is very simple, the first parameter is the file path, the second is the file mode, and several other methods are provided in the man manual.

ssize_t read(int fd, void *buf, size_t count);

The first parameter is the file descriptor, which is the value returned by open

The second parameter buf is used to store the content read from the file

The third parameter indicates the content you want to read from the file (note: the count number can be given at will, and finally the actual number returned (the return value of read) shall prevail

2) Open and write files

1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 #include <string.h>
 7 
 8 int main(int argc, char const *argv[]) {
 9 
10     int fd = -1; //文件描述符
11 
12     //打开文件
13     fd = open( "ghostwu.txt", O_RDWR );
14 
15     if ( -1 == fd ) {
16         printf("文件打开失败\n");
17     }else {
18         printf("文件打开成功,fd=%d\n", fd );
19     }
20 
21     //写文件
22     char buf[] = "I love Linux, Linux is very very good!!!";
23     int count = 0;
24     count = write( fd, buf, strlen( buf ) );
25     if ( -1 == count ) {
26         printf("文件写入失败\n");
27     }else {
28         printf("文件写入成功,实际写入的字节数目为:%d\n", count);
29     }
30 
31     //关闭文件
32     close( fd );
33 
34     return 0;
35 }

ssize_t write(int fd, const void *buf, size_t count);

The first parameter is the file descriptor, which is the value returned by open

The second parameter buf is used to store the written content

The third parameter indicates the size of the file to be written

3) Some flag parameters of open

1, read-only and write-only permissions

1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 
 7 int main(int argc, char const *argv[]) {
 8 
 9     int fd = -1; //文件描述符
10 
11     //打开文件, O_RDONLY:只读权限,打开之后的文件只能读取,不能写入
12     //打开文件, O_WRONLY:只写权限,打开之后的文件只能写入,不能读取
13     // fd = open( "ghostwu.txt", O_RDONLY );
14     fd = open( "ghostwu.txt", O_WRONLY );
15 
16     if ( -1 == fd ) {
17         printf("文件打开失败\n");
18     }else {
19         printf("文件打开成功,fd=%d\n", fd );
20     }
21 
22     //读取文件
23     int count = 0;
24     char buf[41];
25     count = read( fd, buf, 38 );
26     if ( -1 == count ) {
27         printf("文件读取失败\n");
28     }else {
29         printf("文件读取成功,实际读取的字节数目为:%d\n内容为%s\n", count, buf );
30     }
31 
32     //关闭文件
33     close( fd );
34 
35     return 0;
36 }

2, clear and append

1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 #include <string.h>
 7 
 8 int main(int argc, char const *argv[]) {
 9 
10     int fd = -1; //文件描述符
11 
12     //打开文件
13     //在O_RDWR模式下,对于一个已经存在的文件,且有内容,那么写入文件会覆盖对应大小的源文件内容【不是完全覆盖】
14     // fd = open( "ghostwu.txt", O_RDWR );
15     //在具有写入权限的文件中,使用O_TRUNC 会先把原来的内容清除,再写入新的内容
16     // fd = open( "ghostwu.txt", O_RDWR | O_TRUNC );
17     //在具有写入权限的文件中,使用O_APPEND 会把新内容追加到原来内容的后面
18     // fd = open( "ghostwu.txt", O_RDWR | O_APPEND );
19 
20     //在具有写入权限的文件中,使用O_APPEND和O_TRUNC O_TRUNC起作用,会把原来的内容清除,再写入新的内容
21     fd = open( "ghostwu.txt", O_RDWR | O_APPEND | O_TRUNC );
22 
23     if ( -1 == fd ) {
24         printf("文件打开失败\n");
25         return -1;
26     }else {
27         printf("文件打开成功,fd=%d\n", fd );
28     }
29 
30     //写文件
31     char buf[] = "new content";
32     int count = 0;
33     count = write( fd, buf, strlen( buf ) );
34     if ( -1 == count ) {
35         printf("文件写入失败\n");
36         return -1;
37     }else {
38         printf("文件写入成功,实际写入的字节数目为:%d\n", count);
39     }
40 
41     //关闭文件
42     close( fd );
43 
44     return 0;
45 }

3, Whether the file exists or not, create a file and set permissions

1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 #include <errno.h>
 7 
 8 int main(int argc, char const *argv[]) {
 9 
10     int fd = -1;
11 
12     // fd = open( "ghostwu.txt", O_RDWR | O_CREAT | O_EXCL );
13 
14     /*
15         文件不存在:
16             创建这个文件 并打开成功
17         文件存在:
18             再次运行时(文件已经创建成功,存在了), 这时打开失败
19     */
20     // fd = open( "ghostwu.txt", O_RDWR | O_CREAT );
21 
22     fd = open( "ghostwu.txt", O_RDWR | O_CREAT | O_EXCL, 666 );
23 
24     if( -1 == fd ) {
25         printf("文件打开失败,错误号:%d\n", errno );
26         perror( "open" );
27         return -1;
28     }else {
29         printf("文件打开成功\n");
30     }
31 
32     close( fd );
33 
34     return 0;
35 }

A function perror, errno and perror are used above:

1) errno is the error number, which means the wrong number. In the linux system, various common errors are numbered. When the function is executed incorrectly, the function will return a specific errno number to tell us where the function is wrong.

2) errno is a global variable maintained by the operating system. The internal functions of the operating system can tell the upper layer caller what error just happened by setting errno

3) errno itself is essentially a number of int type, and each number corresponds to an error. When we only look at errno, we can only get an error number, and we don’t know where the error is. Therefore: the linux system provides a function perror (meaning print error), and the perror function will read errno and recognize this badly. The number is directly converted into the corresponding error message string, and then printed out

4, lseek is used to move the internal pointer of the file

Simple Application: Statistical File Size

1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 #include <errno.h>
 7 
 8 int main(int argc, char const *argv[]) {
 9 
10     if ( argc != 2 ) {
11         printf("usage:%s %s\n", argv[0], "filename");
12         return -1;
13     }
14 
15     int fd = -1;
16 
17     fd = open( argv[1], O_RDWR );
18 
19     if( -1 == fd ) {
20         printf("文件打开失败,错误号:%d\n", errno );
21         perror( "open" );
22         return -1;
23     }else {
24         printf("文件打开成功\n");
25     }
26 
27     //把指针移动到文件末尾,就是文件的大小
28     int count = lseek( fd, 0, SEEK_END );
29 
30     printf("文件大小为%d\n", count);
31 
32     close( fd );
33     return 0;
34 }

------------------------------------------Dividing line------ ------------------------------------

1. The same process opens the same file multiple times, and the result of reading out the content is: Read separately【When we use open to open the same file twice, the file pointers corresponding to fd1 and fd2 are different and independent pointer】

1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <errno.h>
 6 #include <unistd.h>
 7 
 8 int main(int argc, char const *argv[]) {
 9 
10     int fd1 = -1;
11     int fd2 = -1;
12     char buf1[20] = {0};
13     char buf2[20] = {0};
14     int count1 = 0;
15     int count2 = 0;
16 
17     fd1 = open( "ghostwu.txt", O_RDWR );
18 
19     if ( -1 == fd1 ) {
20         printf("文件打开失败\n");
21         perror( "open" );
22         return -1;
23     }else {
24         printf("文件打开成功,fd1=%d\n", fd1);
25     }
26 
27     count1 = read( fd1, buf1, 5 );
28     if ( -1 == count1 ) {
29         printf( "文件读取失败\n" );
30         perror( "read" );
31     }else {
32         printf( "文件读取成功,读取的内容是%s\n", buf1 );
33     }
34 
35     fd2 = open( "ghostwu.txt", O_RDWR );
36 
37     if ( -1 == fd1 ) {
38         printf("文件打开失败\n");
39         perror( "open" );
40         return -1;
41     }else {
42         printf("文件打开成功,fd2=%d\n", fd1);
43     }
44 
45     count2 = read( fd2, buf2, 10 );
46     if ( -1 == count2 ) {
47         printf( "文件读取失败\n" );
48         perror( "read" );
49     }else {
50         printf( "文件读取成功,读取的内容是%s\n", buf2 );
51     }
52 
53     close( fd1 );
54     close( fd2 );
55 
56     return 0;
57 }

2. The same process opens the same file multiple times, and then the result of writing the content is: write separately, when using O_APPEND, it is to continue writing

View Code

The above code remains unchanged, and the flag is added when writing:

fd1 = open( "ghostwu.txt", O_RDWR | O_APPEND );

fd2 = open( "ghostwu.txt", O_RDWR | O_APPEND );

3. The fd after dup and the fd that originally opened the file point to the same file, and when writing to this file at the same time, it is written next

View Code

In the Linux system, the kernel occupies the three fds of 0, 1, and 2. When we run a program and get a process, 3 files are opened by default internally.

The corresponding fd is 0, 1, 2. They are called stdin, stdout, and stderr respectively. That is, standard input, standard output, and standard error. Next, we turn off the standard output, and printf will not output. If you use dup to copy the original fd, then the fd from the new dup is 1 (corresponding to standard output)

After that, the content of the standard output will be written to the file corresponding to the original fd

View Code

Kernel information through train: Linux kernel source code technology learning route + video tutorial code information

Learning through train: Linux kernel source code/memory tuning/file system/process management/device driver/network protocol stack

Original Author: Extreme Linux Kernel

Original address: Linux Kernel: Process Management - IO Operation Management - Zhihu (copyright belongs to the original author, please contact to delete the infringement message)

 

Guess you like

Origin blog.csdn.net/m0_74282605/article/details/130116775