数据完整性保证

数据完整性保证

1. 介绍

在计算机项目开发中,数据的完整性和持久性是至关重要的。
比如:在多进同时对日志文件进行写入的时候,如何避免日志信息的混乱,进程A写入的信息被进程B写入的信息覆盖。以及在电脑断电的情况下,尽力避免数据的丢失。

2. 写操作相关函数

2.1 write()函数

原型:
ssize_t write(int fd, const void *buf, size_t count);

参数说明:

  • fd:文件描述符
  • buf:指向要写入数据的缓冲区的指针
  • count:要写入的字节数

详细介绍:

  1. 描述:write()函数是系统调用,用于向文件描述符写入数据。
  2. 特点:直接操作内核缓冲区,没有用户空间的缓存,它会尽可能快地将数据写入到文件中,而不会等待或延迟。这使得它非常适合于需要即时写入数据的场景,如实时日志记录或网络通信。
  3. 使用场景:适用于需要直接与操作系统内核交互,或需要精确控制数据写入时机 的低级操作。适合于:图像,音频,视频等。
  4. 功能:基本的二进制写入,不支持格式化或批量操作,每次调用直接将数据写入文件描述符
  5. 错误处理:write()返回写入的字节数。

示例:

#include <unistd.h>  
#include <string.h>  
#include <stdio.h>  
  
int main() {  
    // 尝试写入字符串(不是格式化输出,但写入字符串)  
    char str[] = "Hello, world!你好,世界。";  
    write(STDOUT_FILENO, str, strlen(str));
    write(STDOUT_FILENO, "\n", 1); // 写入换行符  

    int num=42;
    write(STDOUT_FILENO,&num,sizeof(int));// 将整数 42 以二进制形式写入到标准输出(控制台)
    write(STDOUT_FILENO, "\n", 1); // 写入换行符  

    // 尝试批量数据处理(写入整型数组作为字节序列)  
    int nums[] = {1, 2, 3, 4, 5};  
    write(STDOUT_FILENO, (char *)nums, sizeof(nums)); // 强制转换为 char* 并写入整个数组  
  
    return 0;  
}

显示结果:
在这里插入图片描述

发现num(42)的显示结果为:* (ASCII码第42号)
而nums数组却无法打印(1-5是特殊字符)

2.2 fwrite()函数

  1. 原型:
    size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

  2. 参数说明:

    • ptr:指向要写入数据的缓冲区指针
    • size:每个数据项的大小(以字节为单位)
    • nmemb:数据项的个数
    • stream:文件流指针。
  3. 示例:

    #include <stdio.h>
    
    int main() {
        // 格式化输出示例
        FILE *file_format = fopen("output_format.txt", "w");
        if (file_format) {
            int num = 123;
            float pi = 3.1415926;
            char str[] = "Hello, world!";
            fprintf(file_format, "Number: %d\n", num);
            fprintf(file_format, "Pi: %f\n", pi);
            fprintf(file_format, "String: %s\n", str);
            fclose(file_format);
        }
    
        // 批量数据处理示例
        FILE *file_batch = fopen("output_batch.bin", "wb");
        if (file_batch) {
            int nums[] = {1, 2, 3, 4, 5};
            fwrite(nums, sizeof(int), 5, file_batch);
            fclose(file_batch);
        }
    
        return 0;
    }
    
  4. 详细介绍:

    1. 描述:fwrite()是C标准库的一部分,提供了对文件的高级写入功能。
    2. 特点:使用用户空间的缓冲,可以减少系统调用的次数,提高写入效率。这意味着实际的写入可能会延迟发生,直到缓冲区满或者显示的调用fflush()
    3. 使用场景:格式化输出,批量处理数据等。
    4. 功能:支持格式化和批量处理数据,可以一次写入多个数据项。
    5. 错误处理:fwrite()返回写入的项数,如果小于请求的项数,可能是发生了错误或者文件结束。
  5. 工作流程
    fwrite(arr)为例:

    1. fwrite()会把arr中的数据复制到标准C库的用户空间缓冲区中。
    2. 标准C库会管理这个用户空间缓冲区,可能会等待缓冲区填满或者手动调用fflush()才会触发数据的写入操作。
    3. 当标准库认为合适的时候,会通过系统调用(write)将用户空间缓冲区的数据传递给内核空间。
    4. 内核空间收到数据后,进一步对数据写入,最终把数据写入到磁盘中。

    优点:
    假设你有一个程序,需要将大量数据写入到文件中。如果没有使用缓冲机制,每次写入一个数据项都会触发一个系统调用,这样频繁的系统调用会导致系统开销增加,降低写入效率。
    现在,假设你使用了缓冲机制,比如标准C库的 fwrite() 函数。当你调用 fwrite() 写入数据时,数据首先被复制到用户空间的缓冲区中。在缓冲区填满之前,所有的写入操作都只是在用户空间进行,没有触发系统调用。只有当缓冲区填满、达到一定大小,或者手动调用 fflush() 函数时,才会触发系统调用,将缓冲区中的数据一次性写入到内核空间。
    这样一来,多个数据项被聚集成一个更大的块,一次性写入到内核空间,从而减少了系统调用的次数。相比每次写入一个数据项都触发系统调用,这种批量写入的方式会显著减少系统调用的频率。

3. 数据写同步

3.1 sync()

  1. 原型:
    void sync(void)
  2. 描述:
    sync()是一个系统调用,用于将所有修改过的文件缓冲区写入硬盘。这个函数是全局性的触发所有缓冲区的写操作。
  3. 使用场景
    当需要确保整个系统的所有文件数据都安全写入硬盘时使用,例如在系统关机前。

3.2 fsync()

  1. 原型:
    int fsync(int fd)
  2. 描述:
    fsync()针对单一的文件描述符fd,确保该文件描述符引用的文件的所有内存中的数据和元数据(比如文件修改时间等属性)都被写入存储设备。
  3. 使用场景
    在需要确保特定文件数据被安全写入存储设备时使用,常见于数据库管理系统和文件编辑器,保证关键数据的持久性和一致性。

3.3 fdatasync()

  1. 原型:
    int fdatasync(int fd);
  2. 描述:
    fdatasync()类似于fsync(),但它只确保文件的数据部分被同步到硬盘,不包括与文件相关的元数据(除非这些元数据的改变是由于文件数据更新所必需的)。
  3. 使用场景:
    当不需要文件元数据(如最后的访问时间)被同步时使用。这通常用于提高性能,因为同步较少的数据可以减少I/O操作的数量。适用于例如数据库日志文件的写入,其中只关心数据的持久性,而不关心文件的元数据。
  • 13
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值