Unix系统编程(一)

时间:2022-09-08 14:47:29

主要内容:文件输入/输出的系统调用。

 

在Linux中,万事万物皆文件。

 

文件描述符的概念

 

通用I/O模型的系统调用:

打开文件 open

关闭文件 close

向文件写数据 write

从文件读数据 read

 

这些系统调用不仅可以对普通的文件类型进行操作,也可以对管道、终端等所有类型的文件施以输入/输入操作。

 

所有执行I/O操作的系统调用都以文件描述符,一个非负整数(通常是小整数),来指代打开的文件。

用文件描述符表示所有类型的已打开文件,包括管道(pipe)、FIFO、socket、终端、设备和普通文件。(至今只操作过普通文件,其他几个类型还没接触过)

 

针对每个进程,文件描述符都自成一套。(没看懂)

 

3个标准的文件描述符

 

当在shell中操作的时候,有3个文件描述符始终是打开的。

在交互式的shell中,这个3个文件描述符通常指向shell运行所在的终端。(就是我们远程连接时候的屏幕?)

 

如果命令行制定对输入/输出进行重定向操作,那么shell会对文件描述符做适当修改,然后再启动程序。

 

文件描述符             用途               POSIX名称                     stdio流

0                        标准描述符         STDIN_FILENO              stdin

1                         标准输出            STDOUT_FILENO          stdout

2                         标准错误            STDERR_FILENO           stderr

 

这里的意思是虽然shell开始会用0,1,2来这三个文件描述符代替标准输入,标准输入和标准错误,但是这种操作就像是给变量赋初始值一样。这些文件描述符并没有绑死,而是可以用freopen系统调用指向其他的任何文件对象。

 

fd = open(pathname, flags, mode)

打开pathname所标识的文件,并返回文件描述符,这个文件描述符就代表了打开的文件,并且在函数调用中用这个描述符就好了。

如果要打开的文件不存在,open()函数可以创建它,但是这取决于flags中的选项。

flags还指定了文件的打开方式:只读、只写或者是读写方式。

mode指定了由open()调用创建文件的访问权限(u,o,g,w, x,r),如果open()函数并没有创建文件,那么可以忽略或省略mode参数。

马丹,这块不熟,一个系统调用涉及到的东西这么多。

 

numread = read(fd, buffer, count)

从fd所指代的文件读取至多count字节的数据,并存储到buffer中。read()调用的返回值为实际读取到的字节数。如果再无字节可读(例如:读到文件结尾符EOF时),则返回0。

 

numwrite = write(fd, buffer, count)

从buffer中读取多达count字节的数据写入由fd指代的已打开文件中,write()调用的返回值为实际写入文件中的字节数,且有可能小于count。

 

status = close(fd)

在所有的输入/输出操作完成以后,调用close(),释放文件描述符fd以及与之相关的内核资源。

 

例子:用通用I/O系统调用实现一个简版的cp命令

 1 #include <unistd.h>
 2 #include <stdio.h>
 3 #include <sys/stat.h>
 4 #include <sys/types.h>
 5 #include <fcntl.h>
 6 
 7 int main(int argc, char **argv) {
 8   int fd1, fd2, count=0;
 9   char bufs[512];
10 
11   if(argc < 2) {
12     printf("Usage is error: ./mycp argv1 argv2.\n");
13     return -1;
14   }
15 
16   fd1 = open(argv[1], O_RDONLY, 0755);
17   if(fd1 < 0) {
18     printf("open %s error\n", argv[1]);
19     return -1;
20   }
21 
22   fd2 = open(argv[2], O_RDWR|O_CREAT, 0755);
23   if(fd2 < 0) {
24     printf("open %s error\n", argv[2]);
25     return -1;
26   }
27 
28   while( (count = read(fd1, bufs, 100)) > 0) {
29     write(fd2, bufs, count);
30   }
31   close(fd1);
32   close(fd2);
33 }

然后,顺手写了一个简单的Makefile,因为这几天在看make。

# this is my Makefile for mycp
mycp: mycp.o
        cc -o mycp mycp.o
mycp.o: cp.c
        cc -c cp.c -o mycp.o

.PHONY: clean
clean:
        -rm mycp mycp.o

好像代码插件没有Makefile,那就先用bash的风格吧