在所有编程语言(至少我使用的)中,必须先打开一个文件,然后才能对其进行读写。

但是这个开放操作实际上是做什么的呢?

典型函数的手册页面实际上没有告诉你任何东西,除了它“打开一个文件进行读写”:

http://www.cplusplus.com/reference/cstdio/fopen/

https://docs.python.org/3/library/functions.html#open

显然,通过使用该函数,您可以知道它涉及到创建某种对象,以方便访问文件。

另一种说法是,如果我要实现一个开放函数,它在Linux上需要做什么?


当前回答

在它的核心,当打开阅读时,实际上不需要发生任何花哨的事情。它所需要做的就是检查文件是否存在,并且应用程序有足够的权限来读取它,并创建一个句柄,您可以在这个句柄上向文件发出读取命令。

正是在这些命令上,实际的读取将被分派。

操作系统通常会通过开始一个读操作来填充与句柄相关的缓冲区来开始读取操作。然后,当您实际执行读取操作时,它可以立即返回缓冲区的内容,而不需要等待磁盘IO。

为了打开一个新文件写操作系统将需要在目录中添加一个新(当前为空)文件的条目。再次创建一个句柄,您可以在其上发出写入命令。

其他回答

简单来说,当您打开一个文件时,您实际上是在请求操作系统将所需的文件(将文件的内容复制到ram中)从辅助存储器加载到ram中进行处理。这背后的原因(加载文件)是因为您不能直接从硬盘处理文件,因为与Ram相比,硬盘的速度非常慢。

open命令将生成一个系统调用,该调用将文件的内容从二级存储(硬盘)复制到主存储(Ram)。

我们“关闭”一个文件,因为修改后的文件内容必须反映到硬盘中的原始文件中。:)

希望这能有所帮助。

在它的核心,当打开阅读时,实际上不需要发生任何花哨的事情。它所需要做的就是检查文件是否存在,并且应用程序有足够的权限来读取它,并创建一个句柄,您可以在这个句柄上向文件发出读取命令。

正是在这些命令上,实际的读取将被分派。

操作系统通常会通过开始一个读操作来填充与句柄相关的缓冲区来开始读取操作。然后,当您实际执行读取操作时,它可以立即返回缓冲区的内容,而不需要等待磁盘IO。

为了打开一个新文件写操作系统将需要在目录中添加一个新(当前为空)文件的条目。再次创建一个句柄,您可以在其上发出写入命令。

记账,主要是。这包括各种检查,如“文件是否存在?”和“我是否有权限打开此文件进行写入?”。

但这些都是内核的东西——除非你正在实现自己的玩具操作系统,没有太多的东西需要深入研究(如果你是,玩得开心——这是一个很好的学习经历)。当然,您仍然应该了解在打开文件时可能收到的所有错误代码,以便正确地处理它们——但这些通常都是不错的小抽象。

代码级别上最重要的部分是,它为您提供了打开文件的句柄,您可以将其用于对文件进行的所有其他操作。难道不能使用文件名来代替这个任意的句柄吗?当然,但使用手柄也有一些好处:

The system can keep track of all the files that are currently open, and prevent them from being deleted (for example). Modern OSs are built around handles - there's tons of useful things you can do with handles, and all the different kinds of handles behave almost identically. For example, when an asynchronous I/O operation completes on a Windows file handle, the handle is signalled - this allows you to block on the handle until it's signalled, or to complete the operation entirely asynchronously. Waiting on a file handle is exactly the same as waiting on a thread handle (signalled e.g. when the thread ends), a process handle (again, signalled when the process ends), or a socket (when some asynchronous operation completes). Just as importantly, handles are owned by their respective processes, so when a process is terminated unexpectedly (or the application is poorly written), the OS knows what handles it can release. Most operations are positional - you read from the last position in your file. By using a handle to identify a particular "opening" of a file, you can have multiple concurrent handles to the same file, each reading from their own places. In a way, the handle acts as a moveable window into the file (and a way to issue asynchronous I/O requests, which are very handy). Handles are much smaller than file names. A handle is usually the size of a pointer, typically 4 or 8 bytes. On the other hand, filenames can have hundreds of bytes. Handles allow the OS to move the file, even though applications have it open - the handle is still valid, and it still points to the same file, even though the file name has changed.

您还可以使用其他一些技巧(例如,在进程之间共享句柄,从而在不使用物理文件的情况下拥有通信通道;在unix系统上,文件也用于设备和各种其他虚拟通道,所以这不是严格必要的),但它们并没有真正绑定到open操作本身,所以我不打算深入研究这一点。

你想谈论的任何文件系统或操作系统我都可以。好了!


在ZX Spectrum上,初始化LOAD命令将使系统进入一个紧密的循环,读取音频。

数据开始由一个常量音调表示,之后是长/短脉冲序列,其中短脉冲表示二进制0,较长脉冲表示二进制1 (https://en.wikipedia.org/wiki/ZX_Spectrum_software)。紧加载循环收集位,直到它填满一个字节(8位),将其存储到内存中,增加内存指针,然后循环回来扫描更多的位。

通常,加载器会读取的第一件事是一个短的、固定格式的头,它至少指示了预期的字节数,以及可能的附加信息,如文件名、文件类型和加载地址。在读取这个短报头后,程序可以决定是继续加载数据的主要部分,还是退出加载例程并为用户显示适当的消息。

可以通过接收任意数量的字节来识别文件结束状态(可以是固定数量的字节,在软件中是硬连接的,也可以是在头文件中指出的可变数量)。如果加载循环在一定时间内没有接收到预期频率范围内的脉冲,则抛出错误。


关于这个答案有一点背景知识

所描述的过程是从普通磁带中加载数据——因此需要扫描audio In(它与磁带录音机的标准插头连接)。LOAD命令在技术上与打开文件相同——但它在物理上与实际加载文件绑定。这是因为磁带录音机不是由计算机控制的,你不能(成功地)打开一个文件而不加载它。

The "tight loop" is mentioned because (1) the CPU, a Z80-A (if memory serves), was really slow: 3.5 MHz, and (2) the Spectrum had no internal clock! That means that it had to accurately keep count of the T-states (instruction times) for every. single. instruction. inside that loop, just to maintain the accurate beep timing. Fortunately, that low CPU speed had the distinct advantage that you could calculate the number of cycles on a piece of paper, and thus the real world time that they would take.

当你打开一个文件时到底会发生什么,这取决于操作系统。下面我将描述在Linux中发生的事情,因为它可以让您了解当您打开一个文件时会发生什么,如果您对更详细的内容感兴趣,您可以检查源代码。我没有涉及权限,因为这会使这个答案太长。

In Linux every file is recognised by a structure called inode. Each structure has an unique number and every file only gets one inode number. This structure stores meta data for a file, for example file-size, file-permissions, time stamps and pointer to disk blocks, however, not the actual file name itself. Each file (and directory) contains a file name entry and the inode number for lookup. When you open a file, assuming you have the relevant permissions, a file descriptor is created using the unique inode number associated with file name. As many processes/applications can point to the same file, inode has a link field that maintains the total count of links to the file. If a file is present in a directory, its link count is one, if it has a hard link its link count will be two and if a file is opened by a process, the link count will be incremented by 1.