C++ 文件流实际上是如何工作的?

C++ 文件流实际上是如何工作的?,c++,c,assembly,file-io,fstream,C++,C,Assembly,File Io,Fstream,我一直在想,文件流究竟是如何工作的?对于文件流,我指的是在不将整个文件加载到内存的情况下访问部分文件。 我相信(C++)知道C++类(i o o)fStuts确实如此,但是它是如何实现的呢?可以自己实现文件流吗? 它是如何在最低C/C++(或支持文件流的任何语言)级别工作的?C函数fopen、fclose、fread和FILE*指针是否已经负责流式处理(即,不将整个文件加载到内存中)?如果不是,你将如何直接从硬盘读取,并且有这样一个在C/C++中实现的设备吗?p> 任何指向正确方向的链接、提示和

我一直在想,文件流究竟是如何工作的?对于文件流,我指的是在不将整个文件加载到内存的情况下访问部分文件。
我相信(C++)知道C++类<代码>(i o o)fStuts确实如此,但是它是如何实现的呢?可以自己实现文件流吗?
它是如何在最低C/C++(或支持文件流的任何语言)级别工作的?C函数
fopen
fclose
fread
FILE*
指针是否已经负责流式处理(即,不将整个文件加载到内存中)?如果不是,你将如何直接从硬盘读取,并且有这样一个在C/C++中实现的设备吗?p> 任何指向正确方向的链接、提示和指针都会非常有用。我在谷歌上搜索过,但谷歌似乎不太明白我在追求什么


忍者编辑:如果有人知道如何在汇编/机器代码级别执行此操作,并且如果可以自己实现,或者如果必须依赖系统调用,那将非常棒。:)不需要回答,尽管有一个正确方向的链接会更好。

在最低级别(至少对于用户代码),您将使用系统调用。在类UNIX平台上,这些功能包括:

  • 打开
  • 关闭
  • 读取
  • write
  • lseek
…和其他人。它们通过传递这些称为文件描述符的东西来工作。文件描述符只是不透明的整数。在操作系统内部,每个进程都有一个文件描述符表,其中包含所有文件描述符和相关信息,例如它是哪个文件、它是什么类型的文件等

还有与UNIX上的系统调用类似的Windows API调用:

  • /
  • /
  • /
Windows传递
HANDLE
s,这类似于文件描述符,但我认为灵活性稍差。(例如,在UNIX上,文件描述符不仅可以表示文件,还可以表示套接字、管道和其他内容)

C标准库函数
fopen
fclose
fread
fwrite
fseek
仅仅是这些系统调用的包装

打开文件时,通常不会将文件的任何内容读入内存。当您使用
fread
read
时,您会告诉操作系统将特定数量的字节读入缓冲区。这个特定的字节数可以是但不一定是文件的长度。因此,如果需要,您只能将文件的一部分读入内存

忍者编辑的答案: 您询问了这在机器代码级别是如何工作的。我只能解释这在Linux和Intel 32位体系结构上是如何工作的。当您使用系统调用时,一些参数被放入寄存器中。将参数放入寄存器后,将引发中断
0x80
。因此,例如,要从
stdin
(文件描述符0)到地址
0xDEADBEEF
,可以使用以下汇编代码:

mov eax, 0x03       ; system call number (read = 0x03)
mov ebx, 0          ; file descriptor (stdin = 0)
mov ecx, 0xDEADBEEF ; buffer address
mov edx, 1024       ; number of bytes to read
int 0x80 ; Linux system call interrupt
int 0x80
引发软件中断,操作系统通常会在中断向量表或中断描述符表中注册该软件中断。无论如何,处理器将跳转到内存中的特定位置。一旦到了那里,操作系统通常会进入内核模式(如果需要的话),然后执行相当于C的
开关
打开
eax
。从那里,它将跳转到
read
的实现中。在
read
中,它通常会从调用进程的文件描述符表中读取有关描述符的一些元数据。一旦它拥有了它所需要的所有数据,它就完成它的工作,然后返回到用户代码

为了“完成它的工作”,让我们假设它是从磁盘读取的,而不是管道或
stdin
或其他非物理位置。我们还假设它正在从主硬盘读取数据。另外,假设操作系统仍然可以访问BIOS中断

要访问该文件,它需要执行一系列文件系统操作。例如,遍历目录树以查找实际文件所在的位置。我不打算讲太多,因为我打赌你能猜到

有趣的部分是从磁盘读取数据,无论是文件系统元数据、文件内容还是其他内容。首先,您得到一个逻辑块地址(LBA)。LBA只是磁盘上数据块的索引。每个数据块通常为512字节(尽管这个数字可能有日期)。仍然假设我们可以访问BIOS并且操作系统使用它,那么它将把LBA转换为CHS符号。CHS(气缸盖扇区)表示法是另一种参考硬盘部件的方法。它过去与物理概念相对应,但现在已经过时,但几乎每个BIOS都支持它。从那里,操作系统将把数据填入寄存器并触发中断,即BIOS的磁盘读取中断


这是我能解释的最低水平,我确信在我假设BIOS中使用的操作系统已经过时之后的部分。在此之前的一切都是它如何工作的,不过,我相信,如果不是简化的话。

在最低级别,在POSIX平台上,打开的文件由用户空间中的“描述符”表示。文件描述符只是一个整数,它在任何给定时间在打开的文件中都是唯一的。描述符用于在请求内核实际执行操作时标识操作应应用于哪个打开的文件。因此,
read(0,charptr,1024)
从与描述符
0
关联的打开的文件中进行读取(按照惯例,这可能是进程的标准输入)

尽用户空间所能