《Linux程序设计》第三章 (系统调用)

许多Linux的shell都允许用户接入自己家的目录,使用cd ~ usr(usr是用户名)命令即可。但是标准库函数不能够理解shell中的~符号。所以必须在自己的程序中使用文件名。

Linux中比较重要的三个设备文件:/dev/console:系统控制台;/dev/tty:控制终端;/dev/null:空设备。

为了向用户提供统一的接口,设备驱动封装了所有与硬件相关的特性。硬件的特有功能通常可以通过ioctl来进行调用。/dev目录中设备文件的用法都是相同的。以下是关于设备驱动程序的底层函数:open,read,write,close,ioctl。但是针对输入输出操作直接使用系统调用会使得效率非常低。因此linux向用户提供了一系列高级的接口。只有当数据长度满足某一个块长度的要求的时候才进行系统调用。

底层文件的访问:当一个程序开始运行的时候,通常有三个文件描述符:0 标准输入;1 标准输出;2 标准错误输出。

1.write系统调用

函数原型:size_t write(int fildes, const void* buf, size_t nbytes);作用是将buf中前nbytes个字符写入fildes关联的缓冲区中。该函数返回实际写入的字节数。如果返回是0,则表示没有写入任何数据。如果返回的是-1,则表示写入错误。例:

#include <unistd.h>
#include <stdlib.h>
int main()
{
 if((write(1,"Here is some data\n",18))!=18){
  write(2,"A write error has happened on file descriptor 1\n",46);
}
exit(0);
}

输出结果为:

jiang@ubuntu:~$ gcc -c write_test.c
jiang@ubuntu:~$ gcc -o write_test write_test.o
jiang@ubuntu:~$ ./write_test
Here is some data

2.read系统调用

函数原型:size_t read(int fildes,void* buf, size_t  nbytes);作用是从fildes关联的文件中读取nbytes个字符,到buf缓冲区中。改函数返回实际读取的字符数。如果返回0则表示没有读取;返回-1表示读取错误。read系统调用的测试实验:

jiang@ubuntu:~$ echo hello world | ./read_test
hello world
jiang@ubuntu:~$ read test | ./read_test
hello there
jiang@ubuntu:~$ ./read_test < draft.txt
Because we don't know when we will die
we get to think of life as an inexhaustible well
Yet everything happens only a certain nujiang@ubuntu:~$ 

3.open系统调用

函数原型:#include<sys/types.h> #include<sys/stat.h> 

int open(const char *path,int oflags);

int open(const char* path,int oflags,mode_t mode);

准备打开的文件路径以作为path传递给函数,打开文件要执行的动作为oflags

oflags是以下三种模式之一:

  • O_RDONLY 以只读模式打开
  • O_WRONLY 以写模式打开
  • O_RDWR 可以读写

4.访问权限的初始值

  • unmask:为执行权提供掩码。4:禁止读;2:禁止写;1:禁止执行;0:读写执行权限都有。访问权的三个数字分别是属主,组合其他用户。
  • close系统调用:函数原型:int close(int fildes);终止文件描述符fildes与其对应文件之间的关联。
  • ioctl系统调用

一个读写文件的程序:首先有一个文件,被命名为file.in。该段c程序为copy_file.c

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

int main()
{
 char c;
 int in,out;
 in = open("file.in",O_RDONLY);//以只读的方式打开file.in文件
 out=open("file.out",O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR);/*以只读的方式打开file.out文件,如果该文件不存在,则创造该文件。之后文件的所有者拥有读和写的权限*/
 while(read(in,&c,1)==1){//read系统调用,将文件从in中读取一个字符到c中
  write(out,&c,1);//从c中读取一个字符,写入out中
}
exit(0)

此时执行命令 gcc -o copy_file copy_file.c

之后执行TIMEFORMAP ="" time ./copy_file,得到输出: TIMEFORMAT="" time ./copy_system
0.00user 0.01system 0:00.01elapsed 85%CPU (0avgtext+0avgdata 1084maxresident)k
0inputs+16outputs (0major+55minor)pagefaults 0swaps

之后执行命令ls -ls  file.in file.out,(该指令的含义是显示file.in和file.out文件,关于-l和-s:

-l:以长格式显示目录下的内容列表。输出的信息从左到右依次包括文件名,文件类型、权限模式、硬连接数、所有者、组、文件大小和文件的最后修改时间等;

-s:显示文件和目录的大小,以区块为单位;

)。得到结果如下:

8 -rw-rw-r-- 1 jiang jiang 6636 Oct  2 06:39 file.in
8 -rw------- 1 jiang jiang 6636 Oct  2 06:39 file.out

另一个读写文件的程序:

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

int main()
{
 char block[1024];
 int in,out;
 int nread;

in=open("file.in",O_RDONLY);//以只读的方式打开file.in文件
/*以只读的方式打开file.out;如果没有,则创建一个文件名为file.out。文件所有者具有读写权限。*/
out=open("file.out",O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR);
while((nread=read(in,block,sizeof(block)))>0){//从in中读block的大小的字符到block中
  write(out,block,nread);//将block中的nread个字符写入out文件中。
}
exit(0);
}

执行gcc -o copy_block copy_block.c
5.其他与文件管理相关的系统调用

  • lseek对文件描述符的指针进行设置。函数原型为:off_t lseek(int fildes, off_t offset, int whence);改函数用于修改文件描述符fildes的指针的位置。offset用来描述偏移值,whence用来描述偏移的模式。whence有以下三种模式:SEEK_SET:绝对偏移;SEEK_CUR:相对当前进行偏移;SEEK_END:相对结尾进行偏移。
  • fstat,lstat,stat系统调用:返回的都是些文件状态信息
  • dup和dup2:文件复制

猜你喜欢

转载自blog.csdn.net/eriHanami/article/details/82924320