读文件fread的问题

fread -从打开的fd中读取数据,并且是有缓存

man page

       #include <stdio.h>
       size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

坑:

  1. fread 不一定返回你想读的长度, 即返回值不一定等于size * nmemb , 即使还没有eof。所以你要判断判断返回值
  2. size 应该等于 1, 什么原因忘了,之前被坑过
while ((bytes = fread (data, 1, 1024, inFile)) != 0)
    MD5_Update (&mdContext, data, 1024);

这样就完蛋了

while ((bytes = fread (data, 1, 1024, inFile)) != 0)
    MD5_Update (&mdContext, data, bytes);

至于fread 和 read 的区别

总所周知的read 是系统调用,没有缓存的,而fread 是glibc提供的方法,以及 fread 会调用 read,但具体区别呢
以下glibc 的源码

_IO_size_t
_IO_fread (void *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp)
{
  _IO_size_t bytes_requested = size * count;
  _IO_size_t bytes_read;
  CHECK_FILE (fp, 0);
  if (bytes_requested == 0)
    return 0;
  _IO_acquire_lock (fp);
  bytes_read = _IO_sgetn (fp, (char *) buf, bytes_requested);
  _IO_release_lock (fp);
  return bytes_requested == bytes_read ? count : bytes_read / size;
}
libc_hidden_def (_IO_fread)
 
#ifdef weak_alias
weak_alias (_IO_fread, fread)
 
# ifndef _IO_MTSAFE_IO
strong_alias (_IO_fread, __fread_unlocked)
libc_hidden_def (__fread_unlocked)
weak_alias (_IO_fread, fread_unlocked)
# endif
#endif

使用strace 分析

void c_read() {
  const uint64_t MAXDATABUFF = 1024;

  FILE *f = fopen("dfs.s","rb");
  unsigned char data[MAXDATABUFF] = {0};
  int bytes;
  while ((bytes = fread (data, 1, 1024, f)) != 0){}
  fclose(f);
}

void os_read() {
  const uint64_t MAXDATABUFF = 1024;

  int fd = open("dfs.s",O_RDONLY);
  unsigned char data[MAXDATABUFF] = {0};
  int bytes;
  while ((bytes = read (fd, data, 1024)) != 0){}
  close(fd);
}

int main(){
    c_read();
}

对比两种方式编译时 -o0 禁止优化
read

brk(0x55ffa6698000)                     = 0x55ffa6698000
openat(AT_FDCWD, "dfs.s", O_RDONLY)     = 3
read(3, "mmap(0x7f45e1822000, 307200, PRO"..., 1024) = 1024
read(3, "0x56272ef19000\nopenat(AT_FDCWD, "..., 1024) = 1024
read(3, "NLY|O_CLOEXEC) = 3\nread(3, \"\\177"..., 1024) = 1024
read(3, "329272, ...}) = 0\nmmap(NULL, 133"..., 1024) = 1024
read(3, "AD|PROT_WRITE, MAP_PRIVATE|MAP_F"..., 1024) = 1024
read(3, "x7f31e0e78000, 1359872, PROT_REA"..., 1024) = 1024
read(3, "        = 0\nbrk(NULL)           "..., 1024) = 381
read(3, "", 1024)                       = 0
close(3)                                = 0
exit_group(0)                           = ?

fread

openat(AT_FDCWD, "dfs.s", O_RDONLY)     = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=6525, ...}) = 0
read(3, "mmap(0x7f45e1822000, 307200, PRO"..., 4096) = 4096
read(3, "AD|PROT_WRITE, MAP_PRIVATE|MAP_F"..., 4096) = 2429
read(3, "", 4096)                       = 0
exit_group(0)                           = ?

对比可见, fread 合并多次调用read

总结

fread 需要检查返回值

posted @ 2020-03-06 00:14  SnailRush  阅读(882)  评论(0编辑  收藏  举报