1.什么是操作系统API
(1)应用层程序通过调用API来调用操作系统中的各种功能,来干活。
(2)学习一个操作系统,其实就是学习使用这个操作系统的API。
(3)linux常用文件IO接口API open打开文件、close关闭文件、write写文件、read读文件、lseek移动文件读写的位置。
2.简单的文件读写实例
(1)打开文件并读文件内容:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd = -1; // fd 就是file descriptor,文件描述符
char buf[100] = {0}; //输出型数组,把读取的数据填充到这个数组里面
int ret = -1;
// 第一步:打开文件
fd = open("a.txt", O_RDWR);
if (-1 == fd) // 有时候也写成: (fd < 0)
{
printf("文件打开错误\n");
}
else
{
printf("文件打开成功,fd = %d.\n", fd);
}
// 第二步:读文件
ret = read(fd, buf, 10);
if (ret < 0)
{
printf("read失败\n");
}
else
{
printf("实际读取了%d字节.\n", ret);
printf("文件内容是:[%s].\n", buf);
}
// 第三步:关闭文件
close(fd);
return 0;
}
(2)打开文件写文件:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd = -1; // fd 就是file descriptor,文件描述符
char writebuf[20] = "l love linux\n"; //输入型参数
int ret = -1;
// 第一步:打开文件
fd = open("a.txt", O_RDWR);
if (-1 == fd) // 有时候也写成: (fd < 0)
{
printf("文件打开错误\n");
}
else
{
printf("文件打开成功,fd = %d.\n", fd);
}
// 第二步:写文件
ret = write(fd, writebuf, strlen(writebuf));
if (ret < 0)
{
printf("write失败.\n");
}
else
{
printf("write成功,写入了%d个字符\n", ret);
}
// 第三步:关闭文件
close(fd);
return 0;
}
3.open函数的flag
(1)linux中文件有读写权限。
O_RDONLY就表示以只读方式打开
O_WRONLY表示以只写方式打开
O_RDWR表示以可读可写方式打开
O_TRUNC属性去打开文件时,新内容会替代原来的内容
O_APPEND属性去打开文件时,新内容附加在后面,原来的内容还在前面
O_CREAT就表示我们当前打开的文件并不存在,我们是要去创建并且打开它
O_EXCL和O_CREAT来结合使用,当这连个标志一起的时候,则没有文件时创建文件,有这个文件时会报错提醒我们
O_NONBLOCK打开一个文件默认就是阻塞式的,希望以非阻塞的方式打开文件
4.文件读写的一些细节
(1)退出程序
第一种;在main用return,一般原则是程序正常终止return 0,如果程序异常终止则return -1。
第一种:正式终止进程(程序)应该使用exit或者_exit或者_Exit之一。
(2)errno和perror
errno:函数执行错误时,函数会返回一个特定的errno编号来告诉我们这个函数到底哪里错了,errno是由OS来维护的一个全局变量,设置errno来告诉上层调用者究竟刚才发生了一个什么错误。
perror:perror函数内部会读取errno并且将这个不好认的数字直接给转成对应的错误信息字符串,然后print打印出来。好的程序风格要懂得使用perror函数,进行错误信息打印。
(3)read和write的count
count和返回值的关系:count参数表示我们想要写或者读的字节数,返回值表示实际完成的要写或者读的字节数。
count再和阻塞非阻塞结合起来,就会更加复杂。如果一个函数是阻塞式的,则我们要读取30个,结果暂时只有20个时就会被阻塞住,等待剩余的10个可以读。
要读取或者写入的是一个很庞大的文件(譬如文件有2MB),我们不可能把count设置为210241024,而应该去把count设置为一个合适的数字(譬如2048、4096),然后通过多次读取来实现全部读完。
lseek函数
(1)文件指针:文件进行读写时,打开这个文件,所以我们读写的所有文件都是动态文件,会通过文件指针来表征这个正在操作的位置。
(2)read和write函数都是从当前文件指针处开始操作的,所以当我们用lseek显式的将文件指针移动后,那么再去read/write时就是从移动过后的位置开始的。
(3)lseek计算文件长度
// 打开一个文件时此时文件指针指向文件开头
// 我们用lseek将文件指针移动到末尾,然后返回值就是文件指针距离文件开头的偏移量,也就是文件的长度了
ret = lseek(fd, 0, SEEK_END);
return ret;