fsync系统调用及示例

fsync – 文件同步

函数介绍

fsync系统调用用于将文件的所有修改强制写入磁盘,确保数据的持久性。它会同步文件的数据和元数据(如修改时间、访问时间等),是保证数据安全的重要函数。掌握fsync系统调用,确保数据安全写入磁盘。了解其功能、用法及示例代码,提升文件操作效率与可靠性。关键词:fsync…

fsync系统调用, 文件同步fsync, Linux fsync使用示例, 如何使用fsync确保数据持久性, fsync函数详解, fsync与数据安全, 理解fsync及其重要性, 使用fsync提高文件操作安全性, fsync在编程中的应用, fsync系统调用实战案例

函数原型

#include <unistd.h>

int fsync(int fd);

功能

将文件描述符对应的文件所有修改(包括数据和元数据)强制写入磁盘。

参数

  • int fd: 文件描述符

返回值

  • 成功时返回0
  • 失败时返回-1,并设置errno:
    • EBADF: 文件描述符无效
    • EIO: I/O错误
    • EINVAL: 文件描述符不支持同步
    • EROFS: 文件在只读文件系统上

相似函数

  • fdatasync(): 只同步文件数据,不同步所有元数据
  • sync(): 同步所有文件系统缓冲区
  • msync(): 同步内存映射文件

示例代码

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>

int main() {
    int fd;
    struct stat stat_buf;
    time_t write_time, sync_time;
    
    printf("=== Fsync函数示例 ===\n");
    
    // 示例1: 基本的文件同步操作
    printf("\n示例1: 基本的文件同步操作\n");
    
    // 创建测试文件
    fd = open("test_fsync.txt", O_CREAT | O_RDWR | O_TRUNC, 0644);
    if (fd == -1) {
        perror("创建测试文件失败");
        exit(EXIT_FAILURE);
    }
    printf("成功创建测试文件,文件描述符: %d\n", fd);
    
    // 写入数据
    const char *data1 = "First line of data\n";
    if (write(fd, data1, strlen(data1)) == -1) {
        perror("写入第一行数据失败");
        close(fd);
        exit(EXIT_FAILURE);
    }
    printf("写入第一行数据: %s", data1);
    
    // 获取写入时间
    time(&write_time);
    printf("写入时间: %s", ctime(&write_time));
    
    // 同步文件到磁盘
    printf("开始同步文件到磁盘...\n");
    time(&sync_time);
    if (fsync(fd) == -1) {
        perror("文件同步失败");
    } else {
        printf("文件同步成功\n");
        printf("同步完成时间: %s", ctime(&sync_time));
    }
    
    // 再写入更多数据
    const char *data2 = "Second line of data\nThird line of data\n";
    if (write(fd, data2, strlen(data2)) == -1) {
        perror("写入更多数据失败");
    } else {
        printf("写入更多数据成功\n");
    }
    
    // 再次同步
    if (fsync(fd) == -1) {
        perror("第二次文件同步失败");
    } else {
        printf("第二次文件同步成功\n");
    }
    
    // 示例2: 同步前后文件状态对比
    printf("\n示例2: 同步前后文件状态对比\n");
    
    // 获取同步前的文件状态
    if (fstat(fd, &stat_buf) == -1) {
        perror("获取文件状态失败");
    } else {
        printf("同步前文件状态:\n");
        printf("  文件大小: %ld 字节\n", stat_buf.st_size);
        printf("  最后修改时间: %s", ctime(&stat_buf.st_mtime));
        printf("  最后访问时间: %s", ctime(&stat_buf.st_atime));
    }
    
    // 写入数据但不同步
    const char *unsynced_data = "Unsynced data\n";
    if (write(fd, unsynced_data, strlen(unsynced_data)) == -1) {
        perror("写入未同步数据失败");
    }
    
    // 再次获取文件状态(可能还未写入磁盘)
    if (fstat(fd, &stat_buf) == -1) {
        perror("再次获取文件状态失败");
    } else {
        printf("写入未同步数据后的文件状态:\n");
        printf("  文件大小: %ld 字节\n", stat_buf.st_size);
    }
    
    // 同步文件
    if (fsync(fd) == -1) {
        perror("同步文件失败");
    } else {
        printf("文件同步完成\n");
    }
    
    // 同步后再次获取文件状态
    if (fstat(fd, &stat_buf) == -1) {
        perror("同步后获取文件状态失败");
    } else {
        printf("同步后文件状态:\n");
        printf("  文件大小: %ld 字节\n", stat_buf.st_size);
        printf("  最后修改时间: %s", ctime(&stat_buf.st_mtime));
    }
    
    // 示例3: 性能对比演示
    printf("\n示例3: 性能对比演示\n");
    
    // 测试不使用fsync的写入性能
    clock_t start_time = clock();
    for (int i = 0; i < 1000; i++) {
        char buffer[50];
        sprintf(buffer, "Line %d: Performance test data\n", i);
        if (write(fd, buffer, strlen(buffer)) == -1) {
            perror("性能测试写入失败");
            break;
        }
    }
    clock_t without_sync_time = clock() - start_time;
    printf("不使用fsync写入1000行数据耗时: %f 秒\n", 
           ((double)without_sync_time) / CLOCKS_PER_SEC);
    
    // 测试使用fsync的写入性能
    start_time = clock();
    for (int i = 1000; i < 2000; i++) {
        char buffer[50];
        sprintf(buffer, "Line %d: Performance test data with sync\n", i);
        if (write(fd, buffer, strlen(buffer)) == -1) {
            perror("性能测试写入失败");
            break;
        }
        if (fsync(fd) == -1) {
            perror("同步失败");
            break;
        }
    }
    clock_t with_sync_time = clock() - start_time;
    printf("使用fsync写入1000行数据耗时: %f 秒\n", 
           ((double)with_sync_time) / CLOCKS_PER_SEC);
    
    printf("注意: fsync会显著降低写入性能,但保证数据安全\n");
    
    // 示例4: 错误处理演示
    printf("\n示例4: 错误处理演示\n");
    
    // 尝试对无效文件描述符同步
    if (fsync(999) == -1) {
        printf("对无效文件描述符同步: %s\n", strerror(errno));
    }
    
    // 尝试对只读文件同步(应该成功)
    int readonly_fd = open("test_fsync.txt", O_RDONLY);
    if (readonly_fd != -1) {
        if (fsync(readonly_fd) == -1) {
            printf("对只读文件同步: %s\n", strerror(errno));
        } else {
            printf("对只读文件同步成功\n");
        }
        close(readonly_fd);
    }
    
    // 示例5: 数据安全重要性演示
    printf("\n示例5: 数据安全重要性演示\n");
    
    // 创建重要的数据文件
    int important_fd = open("important_data.txt", O_CREAT | O_RDWR | O_TRUNC, 0644);
    if (important_fd != -1) {
        printf("创建重要数据文件\n");
        
        // 写入重要数据
        const char *important_data = "Very important data that must not be lost\n";
        if (write(important_fd, important_data, strlen(important_data)) != -1) {
            printf("写入重要数据\n");
            
            // 对于重要数据,必须同步到磁盘
            if (fsync(important_fd) == -1) {
                perror("重要数据同步失败");
            } else {
                printf("重要数据已安全同步到磁盘\n");
            }
        }
        
        close(important_fd);
        unlink("important_data.txt");
    }
    
    // 清理资源
    printf("\n清理资源...\n");
    if (close(fd) == -1) {
        perror("关闭文件失败");
    } else {
        printf("成功关闭文件描述符 %d\n", fd);
    }
    
    if (unlink("test_fsync.txt") == -1) {
        perror("删除测试文件失败");
    } else {
        printf("成功删除测试文件\n");
    }
    
    return 0;
}

fsync系统调用及示例-CSDN博客

此条目发表在linux文章分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注