首页 文章

fread / fwrite以大小和计数为参数的理由是什么?

提问于
浏览
78

我们在这里讨论了为什么fread和fwrite为每个成员计算一个大小并计算并返回读/写成员的数量,而不是仅仅考虑缓冲区和大小 . 我们可以想出的唯一用途是,如果你想读/写一个结构数组,这些结构不能被平台对齐整除,因此已被填充,但这不能保证这个选择在设计中 .

来自FREAD(3):

函数fread()从流指向的流中读取数据的nmemb元素,每个数据字节长,将它们存储在ptr给定的位置 . 函数fwrite()将每个大小为字节长的数据的nmemb元素写入stream指向的流,从ptr给出的位置获取它们 . fread()和fwrite()返回成功读取或写入的项目数(即,不是字符数) . 如果发生错误或达到文件结尾,则返回值为短项目计数(或零) .

7 回答

  • 12

    它基于fread的实现方式 .

    单UNIX规范说

    对于每个对象,应对fgetc()函数进行大小调用,并按顺序读取存储在unsigned char数组中的结果,该数组与对象完全重叠 .

    fgetc也有这个说明:

    由于fgetc()对字节进行操作,因此读取由多个字节组成的字符(或“多字节字符”)可能需要多次调用fgetc() .

    当然,这早于UTF-8等花哨的可变字节字符编码 .

    SUS指出,这实际上取自ISO C文件 .

  • 18

    fread(buf,1000,1,stream)和fread(buf,1,1000,stream)的区别在于,在第一种情况下,如果文件较小并且在文件中,则只获得一个1000字节或nuthin的块 . 第二种情况,你得到文件中的所有内容少于1000字节 .

  • 54

    这是纯粹的推测,但是在那些日子里(有些仍然存在)很多文件系统都不是硬盘上的简单字节流 .

    许多文件系统都是基于记录的,因此为了以有效的方式满足这些文件系统,您必须指定项目数(“记录”),允许fwrite / fread作为记录在存储上运行,而不仅仅是字节流 .

  • 0

    在这里,我来修复这些功能:

    size_t fread_buf( void* ptr, size_t size, FILE* stream)
    {
        return fread( ptr, 1, size, stream);
    }
    
    
    size_t fwrite_buf( void const* ptr, size_t size, FILE* stream)
    {
        return fwrite( ptr, 1, size, stream);
    }
    

    至于 fread() / fwrite() 参数的基本原理,我很久以前就丢失了我的K&R副本,所以我只能猜测 . 我认为可能的答案是Kernighan和Ritchie可能只是认为执行二进制I / O最自然地会在对象数组上完成 . 此外,他们可能认为块I / O更快/更容易实现,或者某些架构上的任何东西 .

    尽管C标准指定 fread()fwrite()fgetc()fputc() 实现,但请记住,标准在K&R定义C之后很久就存在,并且标准中指定的内容可能不在原始设计者的想法中 . 's even possible that things said in K&R' s "The C Programming Language"可能与首次设计语言时的情况不同 .

    最后,这是P.J. Plauger在"The Standard C Library"中对 fread() 所说的话:

    如果size(second)参数大于1,则无法确定该函数是否也读取了大小 - 超出其报告的1个附加字符 . 通常,最好将函数称为fread(buf,1,size * n,stream);而不是fread(buf,size,n,stream);

    基本上,他说 fread() 的界面已被打破 . 对于 fwrite() ,他指出,"Write errors are generally rare, so this is not a major shortcoming" - 我不同意的陈述 .

  • 3

    可能它可以追溯到文件I / O的实现方式 . (在当天回来)在块中写入/读取文件然后一次写入所有内容可能会更快 .

  • 9

    我认为这是因为C缺少函数重载 . 如果有一些,大小将是多余的 . 但是在C中你无法确定数组元素的大小,你必须指定一个 .

    考虑一下:

    int intArray[10];
    fwrite(intArray, sizeof(int), 10, fd);
    

    如果fwrite接受字节数,您可以编写以下内容:

    int intArray[10];
    fwrite(intArray, sizeof(int)*10, fd);
    

    但这只是效率低下 . 您将有sizeof(int)次系统调用 .

    应该考虑的另一点是,您通常不希望将数组元素的一部分写入文件 . 你想要整数或整数 . fwrite返回成功写入的多个元素 . 因此,如果您发现只写了2个低字节的元素,您会做什么?

    在某些系统上(由于对齐),您无法在不创建副本和移位的情况下访问整数的一个字节 .

  • 1

    对于可以避免读取任何部分记录的实现,具有单独的大小和计数参数可能是有利的 . 如果一个人使用像管道这样的单字节读取,即使使用固定格式数据,也必须允许记录分成两次读取的可能性 . 如果可以改为请求例如当有293个字节可用时,每个10字节的最多40条记录的非阻塞读取,并且系统返回290字节(29条完整记录),同时为下一次读取留下3个字节,这将更加方便 .

    我不知道fread的实现在多大程度上可以处理这样的语义,但它们肯定可以用于可以承诺支持它们的实现 .

相关问题