POSIX表示可移植操作系统接口(Portable Operating System Interface of UNIX,缩写为 POSIX ),不带缓存的文件IO操作,于直接调用系统调用(system call)的方式,高效完成文件输入输出。它以文件标识符(整型)作为文件唯一性的判断依据。
ASCI文件I/O:带缓存的文件IO操作,效率低但是易于维护。它以文件指针(FILE*)作为文件唯一性的判断依据。
文件平时存储在块存储设备(类似于硬盘)中的文件系统中(静态文件),open打开一个文件时,linux内核在进程中建立一个打开文件的数据结构,记录打开的文件的信息;内核在内存中申请建立一段内存,并将静态文件的内容从块存储设备读取到特定地址管理存放(动态文件)。
打开文件后对这个文件的读写操作都是针对内存中的动态文件,当对动态文件进行读写后,动态文件和块存储设备中的静态文件不同步,close时关闭动态文件,内核将内存中的动态文件的内容同步到块存储设备的静态文件。
先open打开一个文件,得到一个文件描述符,然后对文件进行write/read操作(或其他操作),最后close关闭文件即可。
文件描述符其实实质是一个数字,当我们open打开一个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回给应用程序一个数字作为文件描述符,这个数字就和我们内存中维护这个动态文件的这些数据结构挂钩绑定上了,以后我们应用程序如果要操作这一个动态文件,只需要用这个文件描述符进行区分。文件描述符的作用域就是当前进程,出了当前进程这个文件描述符就没有意义了。在遵从POSIX的应用程序中,文件描述符0、1、2分别对应STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,因此一个应用程序进程中文件描述符总是从3开始的。
3.1 创建/打开/关闭文件
(1)open()函数
POSIX使用open()函数打开一个文件,使用creat()函数创建一个新文件。open()函数在指定一定参数的情况下,会隐含调用creat()函数创建文件。
int open(const char *file_name, int flags)
int open(const char *file_name, int flags, mode_t mode)
使用四个数字指定创建文件的权限,与linux的权限设置相同,如0755
flags | description |
---|---|
O_RDONLY | 只读 |
O_WRONLY | 只写 |
O_RDWR | 读写 |
O_CREAT | 若欲打开的文件不存在,则创建该文件 |
O_APPEND | 追加的方式打开(定位到文件尾部) |
O_TRUNC | 若文件存在,则长度被截为0 |
O_EXCL | 若O_CREAT也设置,此指令检查文件是否存在:若不存在则建立新文件;若存在则报错 |
O_LARGEFILE | 在32bit系统中,支持大于2G的文件的打开 |
O_DIRECTORY | 若打开的文件不是目录,则报错 |
O_NONBLOCK | 对文件的操作使用非阻塞模式。此方式对FIFO,特殊块设备文件,或特殊字符设备文件有效。 |
O_SYNC | 使每次write都等到物理I/O操作完成,包括由write操作引起的文件属性更新所需的I/O。 |
注意:
(1)O_TRUNC与O_APPEND
(2)O_CREAT与O_EXCL
(3)O_NONBLOCK
(4)O_SYNC
REF:
https://www.cnblogs.com/suzhou/p/5381738.html
(2) creat()函数
creat()函数的作用是创建新文件,这个基本已经弃用,此函数是为了兼容早期UNIX系统的open()函数。
(3) close()函数
#include
int close(int fd);
关闭文件描述符fd指向的动态文件,并存储文件和刷新缓存。
文件关闭成功返回0,有错误返回-1;
3.2 读写文件
(1) read函数
读取文件内容,并返回实际读取到的字节数
#include
ssize_t read(int fd, void *buf, size_t count)
返回值是零并不代表读取失败,是读到末尾
读取失败是-1
(2) write函数
向文件中写入一定的内容,并返回实际写入文件的字节数
#include
ssize_t write(int fd, void *buf, size_t count)
3.3 文件定位
#include
#include
off_t lseek(int fd, off_t offset, int whence)
修改文件的读写位置,并返回当前文件指针所在的位置
whence | description |
---|---|
SEEK_SET | 文件开始位置 |
SEEK_CUR | 文件当前指针位置 |
SEEK_END | 文件结束位置 |
综合示例:
#include
#include
#include
#include
#include
#include
int main(void)
{
int fd = -1; // fd 就是file descriptor,文件描述符
char buf[100] = {0};
char writebuf[20] = "l love linux";
int ret = -1;
// 第一步:打开文件
fd = open("c.txt", O_RDWR|O_CREAT);//
if (-1 == fd) // 有时候也写成: (fd < 0)
{
perror("文件打开错误");
_exit(-1);
}
else
{
printf("文件打开成功,fd = %d.\n", fd);
}
// 写文件
ret = write(fd, writebuf, strlen(writebuf));
if (ret < 0)
{
perror("write失败");
_exit(-1);
}
else
{
printf("write成功,写入了%d个字符\n", ret);
}
//移动文件指针到开头,因为经过写入之后,文件指针是在末尾,直接读的话是读不到内容的
ret = lseek(fd, 0, SEEK_SET);//
// 读文件
ret = read(fd, buf, 5);
if (ret < 0)
{
perror("read失败");
_exit(-1);
}
else
{
printf("实际读取了%d字节.\n", ret);
printf("文件内容是:[%s].\n", buf);
}
//关闭文件
close(fd);
return 0;
}
REF:
https://www.cnblogs.com/Jimmy1988/p/7488709.html
https://blog.51cto.com/9291927/1796527
https://www.jb51.net/article/94783.htm
https://www.xuebuyuan.com/1389112.html