文件读写与缓存机制
写文件:
1:stdio函数库
fopen/fwrite/fflush/fclose File* fp
2: POSIX系统级别函数
open/write/close fd
3:Windows系统级别函数
CreateFile/WriteFile/CloseHandle
**同步数据到磁盘:**FlushFileBuffers、fsync
使用stdio函数库操作文件,标准库会在用户空间中维护一个缓冲区(缓存)。这种缓冲机制是为了提高性能,减少系统调用的次数,因为系统调用有一定的开销。
缓冲机制的工作原理
写操作:
当使用 fwrite()
、fprintf()
等函数向文件写入数据时,数据首先被写入到标准库在用户空间中分配的缓冲区中。缓冲区满了之后,标准库会自动将缓冲区中的内容刷新到内核缓冲区上,并清空用户空间的缓冲区。也可以手动调用 fflush() 函数或 fclose() 函数来立即刷新缓冲区。
读操作:
当使用 fread()
、fgets()
等函数从文件读取数据时,数据会被读入到用户空间的缓冲区中。之后的读操作会从缓冲区中读取数据,直到缓冲区中的数据被读完,才会再次从内核缓冲区读取新的数据块到缓冲区中。
C标准库提供了三种类型的缓冲
全缓冲(full buffering):
对于那些能够定位(如磁盘文件)的文件,默认情况下使用全缓冲。缓冲区的大小通常较大,只有在缓冲区满时才刷新到内核缓冲区。
行缓冲(line buffering):
对于标准输入/输出(如stdin、stdout),默认使用行缓冲。
当遇到换行符时,缓冲区中的内容会被刷新到内核缓冲区。无缓冲(no buffering):
对于标准错误输出(如stderr),默认情况下不使用缓冲。
每次写入操作都会直接写入到磁盘。
实际写入磁盘
当数据被复制到内核缓冲区后,内核会根据其自身的调度策略决定何时真正将数据写入物理磁盘。内核通常会合并多个写入操作,以提高效率。此外,内核还可能延迟写入操作,直到有足够多的数据需要写入,或者直到某个特定的时间间隔过去。
强制写入磁盘
如果希望确保数据立即写入到物理磁盘上,而不是仅仅写入到内核缓冲区,需要使用特定的函数来同步内核缓冲区。在Windows中,可以使用 FlushFileBuffers() 函数来强制将内核缓冲区中的数据写入磁盘。在POSIX系统中,可以使用 fsync()
或 fdatasync()
函数来达到同样的目的。
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
int main() {
int fd;
const char *filename = "testfile.txt";
const char *data = "Hello, POSIX!";
ssize_t bytes_written;
// 打开文件以写入模式
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd == -1)
{
perror("Failed to open file");
return 1;
}
// 写入数据
bytes_written = write(fd, data, strlen(data));
if (bytes_written != (ssize_t)strlen(data))
{
perror("Failed to write to file");
close(fd);
return 1;
}
// 强制将数据写入磁盘
if (fsync(fd) == -1)
{
perror("Failed to fsync");
close(fd);
return 1;
}
// 关闭文件
if (close(fd) == -1)
{
perror("Failed to close file");
return 1;
}
return 0;
}
文件写入磁盘完整流程:
第一步: 数据首先写入到用户空间缓冲区。
第二步: 当缓冲区满或显式调用刷新函数时,数据被复制到内核缓冲区。
第三步: 要确保数据实际写入到物理磁盘,需要使用 fsync()
(POSIX)或 FlushFileBuffers()(Windows)来同步内核缓冲区。
面试题
写文件时进程宕机,数据是否会丢失?
答案:
-
使用stdio函数库,在进程宕机的时候,如果没有调用 fflush 或者 fclose 函数,那么数据丢失,如果调用了,就要看机器是否掉电,如果机器没掉电,那么数据不会丢失,如果机器掉电了,那么数据有可能丢失。
-
使用系统级别函数库,在调用write函数后进程宕机,如果机器没掉电,因为数据已经到了内核缓冲区,此时数据不会丢失;如果机器掉电,那么数据有可能丢失。