1

fopen当您在代码中执行操作时,我对操作系统实际上如何在 C 中“打开”文件感到困惑。详细地说,假设我有一个 100 个二进制文件(比如 size 1 MB),我用 C 打开

FILE **fptr;

fptr = calloc(100, sizeof(FILE *));

for (ii = 0; ii < 100; ii++) 
   fptr[ii] = fopen(filename[ii], "rb+");

假设filenameii已经被适当地定义。

操作系统会加载100 MB到内存中,还是上面的代码只是告诉程序保持这些文件准备好访问?

4

4 回答 4

3

后者,在需要之前不会从文件中读取数据,即当您调用fread()或其他一些 I/O 函数时。

当然,底层操作系统可能会决定在打开文件时推测性地读取数据,以节省以后的时间,但这不在您的控制范围内,因此实际上没关系。我的意思是这并不重要,因为这种推测性缓冲使用的任何内存都需要立即提供给应用程序按需使用。

也就是说,似乎任何实用系统都不会让fopen()花时间读取 100 MB,但这将是非常糟糕的工程。

另请注意,单个进程可以并行打开的文件数量可能存在限制。不过,对于大多数现代系统来说,100 应该没问题。

于 2013-05-15T10:21:41.303 回答
1

该文件在打开时未加载到内存中。相反,每次读取都会加载部分。对 fopen 的调用不应导致从媒体读取文件内容,现在 fread 将导致从媒体中部分读取(或小文件的完整读取)。部分读取通常等于缓存管理器中的缓存行大小。

于 2013-05-15T10:32:10.690 回答
0

我们需要先看几件事

  1. 文件

这是类型定义如下

stdio.h:

 typedef struct _IO_FILE FILE;

下一个 _IO_FILE

_IO_FILE 如下所示:

libio.h:

struct _IO_FILE {
  int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

  /* The following pointers correspond to the C++ streambuf protocol. */
  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  char* _IO_read_ptr;   /* Current read pointer */
  char* _IO_read_end;   /* End of get area. */
  char* _IO_read_base;  /* Start of putback+get area. */
  char* _IO_write_base; /* Start of put area. */
  char* _IO_write_ptr;  /* Current put pointer. */
  char* _IO_write_end;  /* End of put area. */
  char* _IO_buf_base;   /* Start of reserve area. */
  char* _IO_buf_end;    /* End of reserve area. */
  /* The following fields are used to support backing up and undo. */
  char *_IO_save_base; /* Pointer to start of non-current get area. */
  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  char *_IO_save_end; /* Pointer to end of non-current get area. */

  struct _IO_marker *_markers;

  struct _IO_FILE *_chain;

  int _fileno;
#if 0
  int _blksize;
#else
  int _flags2;
#endif
  _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */

#define __HAVE_COLUMN /* temporary */
  /* 1+column number of pbase(); 0 is unknown. */
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];


  /*  char* _save_gptr;  char* _save_egptr; */

  _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

并且内部指针链继续存在,但是这个文件结构绝不会保留数据,它维护的是记录的快照并呈现给用户空间。万一当用户请求从文件中读取数据时,将使用相同的 FILE * 但是数据将由系统调用检索(在 linux 情况下为读取调用),但是偏移状态将在此处保持自身向前,向后。最重要的是,这为内部系统调用提供了非常好的抽象。

于 2013-05-15T10:55:36.603 回答
-2

它是实现定义的。您不需要在 fopen() 上读取内存中的整个文件。如今,大多数实现都使用某种形式的 mmap() 将数据实际读入内存。

于 2013-05-15T10:24:06.927 回答