本章主要讲解 linux 中的文件、目录及相关操作。
如创建,打开,读写和关闭文件,及如何处理目录。
linux 中,一切都是文件。
那就是,通常程序完全可以像使用文件那样使用磁盘文件,串行口,打印机和其他设备。
大多数情况下,你只需要使用5个基本函数 open,close,read,write 和 ioctl 。
对目录而言,通常上层的 opendir/readdir 接口来读取目录。
linux中比较重要的设备文件有三个
这个设备代表的是系统控制台。
错误信息和诊断信息通畅会被发送到这个设备。
如果一个进程有控制终端的话,那么特殊文件/dev/tty就是这个控制终端(键盘和显示器,或键盘和窗口)的别名。
由于系统自动运行的进程和脚本就没有控制终端,所以他们不能打开/dev/tty。
空设备,是一个特殊的设备文件,它会丢弃一切写入其中的数据,写入它的内容都会永远丢失,而且没有任何可以读取的内容。
因此,null这个设备通常也被称为位桶(bit bucket)或黑洞。
操作系统本身提供的接口,由linux直接提供
包括: open,close,read,write和ioctl(把控制信息传递给设备驱动程序)
定义: 进程直接调用内核暴露出来的的接口的方式称为系统调用
1. 效率低 每次调用都是从用户态进入内核态,然后再返回用户态
2. 硬件限制对底层系统调用一次读取数据的大小。
如磁带机一次读取大小是10k,若传递的不是10k的整数倍,还会以10k存储,会留下空隙。
库函数应运而生,它是一些函数的集合。
调用将内核暴露出来的接口封装好的函数的方法为库函数的调用
系统调用通常是用于底层文件的访问
例如在驱动程序中对设备文件的直接访问,如open read write seek等
库函数是对系统调用的一层封装
因此在用库函数对文件操作的时候,必然会引起系统调用。也就是说,库函数调用实际上是通过系统调用实现的
例如:C库函数fwrite()就是通过write实现的。
运行位置
库函数:在用户态调用,在用户态执行
系统调用函数:在用户态调用,在内核态执行
执行效率
当处理的数据量比较小时,函数库的函数执行效率比较好
因为函数库的函数的作法是将要处理的数据先存入缓冲区内,等到缓冲区装满了,再将数据一次写入或者读出。这种方式处理小量数据时效率比较高。
但是在进行系统调用时,因为用户进程从用户模式进入系统内核模式,中间涉及了许多额外的任务的切换工作,这些操作称为上下文切换,此类的额外工作会影响系统的执行效率。
参考之前的博客:
https://blog.csdn.net/lqy971966/article/details/103657953
0 标准输入
1 标准输出
2 标准错误
#include
size_t write(int fildes, const void *buf, size_t nbytes);
把缓冲区buf的前nbytes个字节写入与文件描述符fildes关联的文件中。
返回实际写入的字节数。
返回0表示未写入任何数据
返回 -1 表示出错。错误代码保存在全局变量errno中。
#include
#include
int main()
{
char str[] = "Hani test\n";
int len = sizeof(str);
if((write(1, str, len)) != len)
write(2, "error\n", 6);
return 0;
}
结果:
root@admindlp-virtual-machine:/home# ./a.out
Hani test
#include
size_t read(int fildes, void *buf, size_t nbytes);
从与文件描述符fildes相关的文件里读入nbytes个字节的数据放到缓冲区buf中。
返回实际读取的字节数。
返回-1,错误。
返回0,表示未读入任何数据。
#include
#include
int main()
{
char buf[128];
int nread;
nread = read(0, buf, 128);
if(nread == -1)
write(2, "read error\n", sizeof("read error\n"));
if((write(1, buf, nread)) != nread)
write(2, "write error\n", sizeof("write error\n"));
return 0;
}
结果:
root@admindlp-virtual-machine:/home# echo hello hani | ./a.out
hello hani