在学习和了解双缓冲时的思考中想到 C++ 中的 std::fstream
也有一个缓冲区, 并且它的 flush
操作与我自己额外实现的缓冲区有何关联?
自己创建的缓冲区是用于将数据累积, 然后一次性写入 std::fstream
的缓冲区, 之后再执行 flush
操作, 以确保数据的写入. 感觉有点多余
随着涉及到文件写入和持久性保证的知识点变多, 并将了解到的信息整理一下(仅限于Linux)
关于数据同步和持久性保证的重要系统调用. 有四个常用的系统调用, 它们分别是 fdatasync
, fsync
, syncfs
和 sync
.
补充说明: 文件分为
元数据部分
和数据部分
元数据部分指的是文件的创建时间,修改时间, 权限等附加的信息
int fdatasync(int fd);
将文件的 数据部分 同步到磁盘, 以确保数据的持久性. 通常用于需要高可靠性的场景, 如数据库日志.
#include
#include
#include
int main() {
std::ofstream file("data.txt");
if (!file.is_open()) {
std::cerr << "Failed to open file." << std::endl;
return 1;
}
// 写入数据到文件
file << "Hello, World!" << std::endl;
// 执行 fdatasync 将数据部分同步到磁盘
int fd = file.rdbuf()->fd();
if (fd != -1) {
if (fdatasync(fd) == -1) {
std::cerr << "Failed to fdatasync." << std::endl;
return 1;
}
}
file.close();
std::cout << "Data is safely on disk." << std::endl;
return 0;
}
int fsync(int fd);
与 fdatasync
类似, 将文件的数据部分和元数据部分同步到磁盘, 提供更高的一致性.
性能开销较大, 因此在需要更高一致性的情况下使用.
#include
#include
#include
int main() {
std::ofstream file("data.txt");
if (!file.is_open()) {
std::cerr << "Failed to open file." << std::endl;
return 1;
}
// 写入数据到文件
file << "Hello, World!" << std::endl;
// 执行 fsync 将数据部分和元数据同步到磁盘
int fd = file.rdbuf()->fd();
if (fd != -1) {
if (fsync(fd) == -1) {
std::cerr << "Failed to fsync." << std::endl;
return 1;
}
}
file.close();
std::cout << "Data and metadata are safely on disk." << std::endl;
return 0;
}
int syncfs(int fd);
将指定文件系统的缓冲区数据同步到磁盘. 为特定文件系统的同步需求提供更为灵活的选择.
#include
#include
#include
int main() {
// 打开文件
int fd = open("data.txt", O_RDWR | O_SYNC);
if (fd == -1) {
std::cerr << "Failed to open file." << std::endl;
return 1;
}
// 写入数据到文件
const char* data = "Hello, World!";
write(fd, data, strlen(data));
// 执行 syncfs 将文件系统的缓冲区数据同步到磁盘
if (syncfs(fd) == -1) {
std::cerr << "Failed to syncfs." << std::endl;
return 1;
}
close(fd);
std::cout << "Data is safely on disk." << std::endl;
return 0;
}
void sync(void);
sync
将所有挂载的文件系统的缓冲区数据刷新到磁盘. 虽然提供较高的数据保障, 但开销较大需要谨慎使用.
#include
#include
int main() {
// 执行 sync 将所有挂载的文件系统的缓冲区数据刷新到磁盘
sync();
std::cout << "All mounted filesystems are synced to disk." << std::endl;
return 0;
}
flush: flush
操作将数据从内存刷新到文件, 但不一定同步到磁盘. 可能会导致数据丢失, 在需要数据持久性的场景下应谨慎使用. (如果是自己写的垃圾日志就用这个, 没必要追求更高的可靠性)
fdatasync: 相对于 flush
提供更高的数据安全性. 将文件的数据部分同步到磁盘降低了数据丢失的风险. 非常适合高可靠性的需求, 如数据库日志.