什么是在C语言中打开文件?

6

在C语言中打开文件时会发生什么?据我所知,当我们打开一个文件时,文件的内容并没有被加载到内存中。它只是设置了文件描述符。那么这个文件描述符是什么呢?如果文件的内容没有加载到内存中,那么文件是如何被打开的呢?


2
你正在使用哪个函数来打开文件? - Thanatos
7个回答

6
通常情况下,如果你使用fopen或(在POSIX系统上)open打开文件,并且函数执行成功,它仅仅会给你一个值(FILE *int),以便在将来的读取函数调用中使用。操作系统可能会在底层读取一些或全部文件内容,也可能不会。无论如何,你必须调用某个函数请求数据进行读取,如果在调用fread/fgets/read等函数时还没有进行读取,则此时进行读取。在POSIX系统中,“文件描述符”通常指open返回的整数。它用于标识已打开的文件。如果你得到一个值为3的文件描述符,在某个地方,操作系统会跟踪3是指向/home/user/dir/file.txt或其他文件的。这是一个简短的值,用于向操作系统指示要从哪个文件进行读取。当你调用open并打开foo.txt时,操作系统会说:“好的,文件已打开,从现在开始称之为3”。

4

这个问题并不完全涉及编程语言。虽然库在打开文件(例如使用openfopen)时会产生影响,但主要的行为来自操作系统。

Linux和其他操作系统在大多数情况下都会执行预读取。这意味着实际上在用户调用read读取文件之前,文件已经从物理存储中读取出来了。这是一种优化方法,减少了用户读取文件所需的时间。程序员可以部分地控制这种行为,使用特定的标志来调用打开函数。例如,Win32 API的CreateFile可以指定FILE_FLAG_RANDOM_ACCESSFILE_FLAG_SEQUENTIAL_SCAN来指定随机访问(此时文件不会预读),或者顺序访问(此时操作系统将执行相当激进的预读取),等等。其他操作系统API可能会提供更多或更少的控制。

对于使用文件描述符的基本ANSI C API openreadwrite,文件描述符是一个简单的整数,传递给操作系统,表示该文件。在操作系统中,这通常被转换为某些包含有关文件的所有必要信息的结构(名称、路径、寻求偏移量、大小、读取和写入缓冲区等)。操作系统将打开文件,即查找与您在open方法中给出的路径对应的特定文件系统条目(在Linux下为inode),创建文件结构,并返回一个ID给用户-文件描述符。从那时起,操作系统可以随意读取任何数据,即使用户没有请求(通常会读取比所请求的更多的数据,至少可以使用文件系统本地大小来工作)。


2

C语言没有文件I/O的原始数据类型,一切都取决于你使用的操作系统和库。


2
fopen 是 C 语言中用于文件 I/O 的原始函数,不依赖于操作系统。(尽管您可以经常调用特定于操作系统的函数以获得更多控制权。) - Thanatos
1
这并不完全正确。 fopen 是一个库函数,而不是原始函数。此外,由于文件访问总是由操作系统完成,因此 fopen 的确取决于操作系统。在某个操作系统上,fopen 可能能够预读或缓冲写入,而在另一个操作系统上可能不能。 - Eli Iser
不仅如此,而且fopen字符串的格式完全取决于操作系统。三个流行的选择使用/、\或:作为分隔符。 - ddyer

1

文件描述符只是抽象的,所有操作都在操作系统上完成。


1
如果程序使用fopen(),则缓冲包将使用特定于实现的系统调用来获取文件描述符,并将其存储在FILE结构中。
系统调用(至少在Unix、Linux和Mac上)将在(通常是)基于磁盘的文件系统上查找文件。它在内核内存中创建数据结构,收集读取或写入文件所需的信息。
它还为每个进程创建一个表,链接到其他内核数据结构以访问文件。这个表的索引是一个(通常很小的)数字。这是从系统调用返回给用户进程的文件描述符,然后存储在FILE结构中。

0

如前所述,这是操作系统的功能。

但对于C文件I/O,您可能需要了解fopen函数的信息。

如果您查看该函数的描述,它会说:

描述:

打开一个流。

fopen打开由文件名指定的文件,并将流与其关联。fopen返回一个指针,用于标识后续操作中的流。

因此,在成功完成时,fopen只返回指向新打开的流的指针。如果出现任何错误,则返回NULL。


0
当您打开文件时,文件指针会获取该文件的基地址(起始地址)。然后,您可以使用不同的函数来处理该文件。 编辑: 感谢Chris,这里是名为FILE的结构。
typedef struct  {
       int             level;      /* fill/empty level of buffer */
       unsigned        flags;      /* File status flags          */
       char            fd;         /* File descriptor            */
       unsigned char   hold;       /* Ungetc char if no buffer   */
       int             bsize;      /* Buffer size                */
       unsigned char   *buffer;    /* Data transfer buffer       */
       unsigned char   *curp;      /* Current active pointer     */
       unsigned        istemp;     /* Temporary file indicator   */
       short           token;      /* Used for validity checking */
}      FILE;   

并不完全正确。对于流(可以是字面文件或其他内容),“文件指针”实际上不是指向文件数据的指针,而是指向存储访问信息的结构体的指针,其中包括底层文件描述符和读取指针。读取指针通常会初始化为文件开头。但是,fopen()函数返回的是指向结构体的指针,而不是指向文件数据的指针。要获取指向文件数据的实际可引用指针,请使用open()获取文件描述符(而不是fopen()),然后使用mmap()映射它。 - Chris Stratton
文件结构取决于操作系统。有些结构可能包含文件起始逻辑扇区和盘片编号,而其他结构可能包含权限和文件名。 - Thomas Matthews

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接