OS本身就有一部分是驱动。API实指就是一些函数,这些函数是由Linux系统提供支持的,由应用层程序来使用的。应用层程序通过调用API来调用操作系统中的各种功能,来干活。学习一个操作系统,其实就是学习这个系统的API 。使用Linux系统来读写文件,手段就是学习Linux系统API中和文件相关
open - 打开或创建文件
read - 从文件中读取数据
write - 向文件写入数据
close - 关闭文件
lseek - 改变文件指针位置
fcntl - 文件控制操作
ioctl - 设备控制操作
stat - 获取文件状态信息
fstat - 获取已打开文件的状态信息
mmap - 将文件映射到内存
unlink - 删除文件
rename - 重命名文件
mkdir - 创建目录
rmdir - 删除目录
opendir - 打开目录流
1.在LInux系统中要操作一个文件,一般是先open打开一个文件,得到一个文件描述符,然后对文件进行读写(或其他操作),最后close关闭文件即可
2.我们对文件进行操作的时候,一定要先打开文件,打开成功之后才能去操作文件,读写完成之后,一定要关闭文件,否则可能会造成文件损坏。
3.文件平时是存在块设备中的文件系统中,我们把这种文件叫做静态文件。当我们open打开一个文件时,LInux内核做的操作包括: 内存在进程中建立了一个打开文件的数据结构,记录下我们打开的文件,内核在内存中申请一段内存,并将静态文件的内容从块设备中读取到内存中特定地址管理存放(叫做动态文件)
4.打开文件后,以后对这个文件的读写操作,都是针对内存中的这一份动态文件的,并不是针对静态文件的。当我们对动态文件进行读写后,此时内存中的动态文件和块设备的静态文件就不同步了,当我们Close关闭动态文件之后,Close内部内核将内存中的动态文件的内容去更新(同步)快设备中的静态文件
5.常见的一些现象:打开一个大文件比较慢,我们写了一半的文件,如果没有点保存,重启直接没了
6.为什么要这么设计? 块设备本身有限制,而内存可以按字节为单位来操作,而且可以随机操作。内存操作很灵活,所以内核操作文件就没有任何限制。
1.文件描述符其实本质上是一个数字,这个数字在一个进程中表示一个特定的含义。当我们open打开一个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回给应用程序一个数字作为文件描述符。这个数字就和我们内存中维护这个动态文件的数据结构挂钩,只需要用这个文件描述符进行区分。
2.一句话讲清楚文件描述符:文件描述符就是用来区分一个程序打开的多个文件。
3.文件描述符的作用域就是当前的进程,出了当前进程这个文件描述符就没有意义了
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#define O_RDWR 02
int main(){
printf ("===========open file demo begin============\n");
int fd = -1;
char buf[100] = {0};
char input_buf[100] = " I love linux";
//open file
// fd is file description
// step 1. open file
fd = open("a.txt",O_RDWR);
// Real-ask brochoure ,use man command such as : man 2 open
if (-1 == fd ){ // sometimes write as fd<0
printf("fail open file\n");
return -1;
}
printf ("success open file\n");
int ret = -1 ;
//step 2. write file
ret = write(fd,input_buf,strlen(input_buf));
if(ret<0){
printf("write fail\n");
}
// write is success but read none ?
// now file pointer in end of file , so let pointer to begin of file;
lseek(fd,0,SEEK_SET);
// step 2. read file
// para1 .fd para2. recieve str para3. read count ;
ret = read(fd,buf,20);
if(-1 == ret) printf("read fail\n");
printf("read size is %d\n",ret);
printf("context is [%s]\n",buf);
// step 3. close file
close(fd);
printf ("===========open file demo close============\n");
}
打开不存在的文件时 :O_CREAT O_EXCL
当我们打开不存在的文件的时候,如果文件名不存在就会提示文件错误 而vim 打开文件时候 如果不存在就创建文件。
open的flag O_CREAT就是为了应付打开一个不存在的文件
当使用 O_CREAT的时候 文件已经存在了 会怎么样?如果这文件存在 就会重新创建一个新的文件,原来的内容的会被消除掉。
这样就会带来一个新的问题:我们本来想创建一个新的文件,但是把新的文件名字不小心设置为老文件名 就会被覆盖。我们希望的效果是如果文件存在,则给我报错,不要去创建。这个效果就要靠 O_EXEL标志一块使用。没有这文件的时候会创建,有这个文件会报错,
新知识点: mode_t mode 用来指定权限 mode 使用四个数字来指定权限,其中后面三个很重要 代表后面的权限。
1.fcntl函数是一个多功能的文件管理的工具箱,接受2个参数和一个变参。第一个参数是fd表示要操作的哪个文件 ,第二个参数是cmd表示要进行哪个命令操作。变参是用来传递参数的,要配合cmd来使用
2.cmd的样子类似于F_XXX,不同的cmd具有不同的功能。
1.看起来使用都是函数,但是:标准IO是C库函数,而文件IO是LInux系统的API封装而来的
2.C语言库函数是API封装而来的。库函数内部也是通过调用API来完成操作的,但是库函数因为多了一层封装,所以比API要更加好用。
3.库函数比API还有一个优势就是:API在不同的操作系统之间是不能通用的,但是C库的函数在不同操作系统中几乎是一样的。所以C库函数具有可移植性而API没有可移植性。
4.性能上和宜用性来看,C库函数一般要好些。譬如IO,文件IO是不带缓存的,而标准IO是带缓存的,因此标准IO比文件IO性能要更高。
常见标准IO库函数有:fopen fclose fwrite ferad fflush fseek
#include <stdio.h>
#define FILE_NAME "tmep.txt"
int main()
{
FILE *fp = NULL;
size_t len = -1;
fp = fopen(FILE_NAME, "r+");
char buf[100] = {0};
if (NULL == fp)
{
/* code */
perror("fopen");
return -1;
}
printf("open success\n");
// opt file
// len = fwrite("abcde",1,5,fp);
// printf("len is %d\n",len);
memset(buf, 0, sizeof(buf));
len = fread(buf, 1, 10, fp);
printf("len is %d\n", len);
printf("buf is %s\n", buf);
fclose(fp);
return 0;
}