假设一个程序正在读取文件F.txt,而另一个程序正在同时写入该文件。
(当我考虑如果我是一名系统程序员时该如何实现此功能)我意识到在以下方面可能存在歧义:
..也许不是那么明显。
因此,我的问题是:
最佳答案
从磁板/闪存单元到本地Java变量,读取一个字节要走很长一段路。这是单个字节传播的路径:
fopen()
读取缓冲区出于性能原因,操作系统完成的大多数文件缓冲都保留在页面缓存中,将最近读取和写入的文件内容存储在RAM中。
这意味着您对Java代码的每次读写操作都是在本地缓冲区中进行的:
FileInputStream fis = new FileInputStream("/home/vz0/F.txt");
// This byte comes from the user space buffer.
int oneByte = fis.read();
页通常是4KB内存的单个块。每个页面都有一些特殊的标志和属性,其中一个是“脏页面”,这意味着该页面具有一些未写入物理介质的修改数据。
一段时间后,当OS决定将脏数据刷新回磁盘时,它将以与原始数据相反的方向发送数据。
每当两个不同的进程将数据写入同一文件时,结果是:
“区域”取决于应用程序使用的内部缓冲区大小。例如,在一个2 MB的文件上,两个不同的进程可能会写:
仅当本地缓冲区的大小为2 MB时,缓冲区重叠和数据损坏才会发生。在Java上,您可以使用Channel IO读取文件,并对内部发生的事情进行细粒度的控制。
许多事务数据库通过发出
sync
operation来强制将某些本地RAM缓冲区的写操作写回到磁盘上。与单个文件有关的所有数据都将刷新回磁板或闪存单元,从而有效地确保在断电时不会丢失任何数据。最后,memory mapped file是一个内存区域,它使用户进程可以绕过用户空间缓冲而直接从页面高速缓存中读写数据。
Page Cache系统对于多任务protected mode OS的性能至关重要,每个现代操作系统(Windows NT或更高版本,Linux,MacOS和* BSD)都支持所有这些功能。