文件IO和标准IO

fwrite, fread, write, 和 read 都是用于文件输入输出的函数,但它们之间存在一些关键区别:

  1. 缓冲与非缓冲:

    • fread 和 fwrite 是带缓冲区的函数,这意味着它们在用户空间和文件之间操作时会利用缓冲区来提高效率。标准I/O库会自动管理这个缓冲区,减少了直接磁盘访问的次数。
    • read 和 write 是系统级的、无缓冲的函数,直接与文件描述符操作,不经过标准I/O库的缓冲区。这使得它们的执行速度可能更快,尤其是在大数据块传输时,但这也意味着程序员需要自己处理缓冲逻辑以优化性能。
  2. 函数来源与接口:

    • fread 和 fwrite 属于C标准库函数,使用文件指针(通过fopen获得)进行操作,提供了较为高级且易于使用的接口。
    • read 和 write 是Unix/Linux系统调用,使用文件描述符(通常通过open获得)进行操作,属于低级接口,提供了更底层的功能。
  3. 数据处理:

    • fread 和 fwrite 更适合处理结构化数据,因为它们可以按数据项的大小和数量来读写,适合读写固定长度的数据结构,如结构体。
    • read 和 write 操作的是字节流,对于处理任意类型的数据(包括文本和二进制)都非常灵活,但在处理复杂数据结构时可能需要手动解析。
  4. 错误处理和返回值:

    • fread 和 fwrite 返回实际读取或写入的元素数量,如果发生错误或到达文件末尾,返回值可能会小于请求的数量。
    • read 和 write 返回实际读取或写入的字节数,负值表示发生了错误(此时可以使用errno获取错误码)。
  5. 文件权限与打开模式:

    • 使用fopen时,无法直接指定文件权限,而open允许直接指定文件的访问权限。
  6. 适用场景:

    • 当需要处理较高层次的文件操作,特别是涉及到结构化数据或者希望利用缓冲提升效率时,推荐使用freadfwrite
    • 对于底层编程、需要精细控制文件访问或者对性能有严格要求的场景,可能会偏向于使用readwrite,尽管这通常需要更多的代码来管理缓冲和错误处理。

综上所述,选择使用哪个函数取决于具体需求,比如是否需要缓冲、数据处理的复杂度以及对性能和控制的需求。

fread函数

fread函数是C语言标准库中用于从文件流中读取数据的一个重要函数。它的原型定义如下:

size_t fread(void *ptr, size_t size, size_t count, FILE *stream);

  • 参数说明:

    • ptr:一个指针,指向接收读取数据的缓冲区。这个缓冲区应该足够大以容纳size * count个字节的数据。
    • size:单个元素的大小,以字节为单位。例如,如果你要读取整数,size应为sizeof(int)
    • count:要读取的元素数量。因此,总共将读取size * count个字节。
    • stream:指向已打开的文件流的指针,该文件先前由fopen打开。
    • 要读取整数,size应为sizeof(int)
    • count:要读取的元素数量。因此,总共将读取size * count个字节。
    • stream:指向已打开的文件流的指针,该文件先前由fopen打开。
  • 功能:

    • fread尝试从文件流stream中读取count个元素,每个元素大小为size字节,并将读取的数据存储到由ptr指向的缓冲区中。如果文件流支持它,这个操作可能是块读取,即一次读取多个元素。
  • 返回值:

    • 成功时,fread返回实际读取的元素数量。如果到达文件末尾或者遇到读取错误,返回值可能小于count。如果发生错误,可以通过调用ferror(stream)来检查错误状态,通过feof(stream)来检测是否到达文件末尾。
  • 注意事项:

    • fread不会自动增加文件位置指示器。如果你在同一个文件流上连续调用fread,除非显式调用如fseekrewind等函数改变位置,否则读取将会从上一次调用结束后的位置继续。
    • 由于fread不区分读取错误和文件末尾,调用者必须通过检查feofferror来确定读取操作的状态。
    • 使用fread时,最好确保缓冲区足够大以容纳所有预期的数据,避免内存溢出。

fwrite函数

size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);

  • 参数说明:

    • ptr:指向要写入数据的缓冲区的指针。这个缓冲区应该包含size * count个字节的数据。
    • size:单个元素的大小,以字节为单位。例如,如果你要写入整数,size应为sizeof(int)
    • count:要写入的元素数量。因此,总共将尝试写入size * count个字节。
    • stream:指向已打开的文件流的指针,该文件由fopen函数打开,并且通常是以写入模式(如"wb")打开的。
  • 功能:

    • fwrite尝试将count个元素,每个元素大小为size字节,从ptr指向的缓冲区写入到文件流stream中。此操作可以是块写入,即一次写入多个元素,这依赖于底层系统的实现和文件的打开模式。
  • 返回值:

    • 成功时,fwrite返回实际写入的元素数量。这个数字可能小于count,如果发生了错误或写入被中断。如果返回值小于count,应该通过调用ferror(stream)来检查是否有错误发生。
  • 注意事项:

    • 在调用fwrite前,确保文件已以适当的模式(如二进制写入"wb")打开,并且文件指针位于期望的写入起始位置。
    • fwrite不会自动刷新缓冲区到磁盘。为了确保数据立即写入磁盘,可以调用fflush(stream)函数。
    • 写入操作可能会受到文件系统缓存的影响,因此即使调用了fwrite,数据也可能并未立即物理写入磁盘。

open函数

#include <fcntl.h>
#include <unistd.h>

int open(const char *pathname, int flags, mode_t mode);

  • 参数说明:

    • pathname:指向包含要打开或创建的文件路径名的字符串指针。
    • flags:指定打开文件的操作模式,可以是以下标志的组合(部分常见标志):
      • O_RDONLY:以只读方式打开。
      • O_WRONLY:以只写方式打开。
      • O_RDWR:以读写方式打开。
      • O_CREAT:如果文件不存在,则创建之。需同时指定mode
      • O_TRUNC:如果文件存在并且以写入模式打开,则将其长度截断为0。
      • O_APPEND:写入时,数据追加到文件末尾而不是覆盖现有内容。
      • 其他更多高级标志,如O_EXCL用于与O_CREAT一起避免文件被意外覆盖等。
    • mode:当与O_CREAT一起使用时,指定新创建文件的权限位。通常使用类似S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH这样的组合来设置所有者、同组用户和其他用户的读写权限。
  • 返回值:

    • 成功时,返回一个非负的文件描述符。
    • 失败时,返回-1,并且可以通过errno变量获取错误代码。

read函数

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

  • 参数说明:

    • fd:要从中读取数据的文件描述符。这是一个非负整数,之前通过open或其他系统调用获得。
    • buf:指向缓冲区的指针,这个缓冲区用于存放从文件描述符中读取的数据。缓冲区必须足够大以容纳count字节的数据。
    • count:要读取的字节数。这是你期望从文件描述符中读取的最大数据量。
  • 功能:

    • read尝试从文件描述符fd中读取最多count个字节的数据,并将其存储到由buf指向的缓冲区中。实际读取的字节数可能少于请求的字节数,这取决于多种因素,比如文件的实际剩余字节数、文件描述符的状态或是否设置了非阻塞模式。
  • 返回值:

    • 成功时,read返回实际读取的字节数。如果返回0,表示到达文件末尾;如果返回-1,则表示发生错误,此时可以通过检查全局变量errno来获取具体的错误代码。
  • 阻塞行为:

    • 默认情况下,如果请求的数据不可立即读取(例如,到达文件末尾或没有数据可读),read函数会在某些类型的文件描述符上阻塞,直到数据可用或发生错误。然而,对于非阻塞模式下的文件描述符,如果当前没有数据可读,read会立即返回,可能返回0(文件末尾)或-1(并且设置errnoEAGAINEWOULDBLOCK)。

write函数

#include <unistd.h>

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

  • 参数说明:

    • fd:要写入数据的文件描述符,一个非负整数,之前通过opensocket等系统调用获得。
    • buf:指向包含要写入数据的缓冲区的指针。
    • count:要写入的字节数,即缓冲区中数据的大小。
  • 功能:

    • write尝试将count个字节的数据从buf指向的缓冲区写入到文件描述符fd所关联的资源中。实际写入的字节数可能小于请求的字节数,这取决于系统缓冲区的可用性、文件系统的限制等因素。
  • 返回值:

    • 成功时,write返回实际写入的字节数。如果返回值小于count,可能是因为部分数据被缓冲等待写入或因其他原因未立即完成写入。
    • 如果返回-1,则表示发生了错误,此时可以通过检查全局变量errno来获取具体的错误代码。
  • 阻塞行为:

    • 对于某些类型的文件描述符,如果缓冲区满或资源暂时不可写,write默认可能会阻塞,直到有更多的空间或资源变为可写。但是,如果文件描述符被设置为非阻塞模式,write在无法立即写入全部数据时可能返回-1,并设置errnoEAGAINEWOULDBLOCK
  • 30
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值