fwite/putc 如何写入磁盘?

Posted

技术标签:

【中文标题】fwite/putc 如何写入磁盘?【英文标题】:How does fwite/putc write to Disk? 【发布时间】:2013-08-10 11:24:45 【问题描述】:

假设我们有一个已经存在的文件,比如<File>。此文件已由 C 程序打开以进行更新 (r+b)。我们使用fseek 导航到<File> 内的一个点,而不是它的末尾。现在我们开始使用fwrite/fputc 写入数据。请注意,我们不会删除以前存在于 <File> 中的任何数据...

系统如何处理这些写入?它是否将整个文件重写到磁盘中的另一个位置,现在包含新数据?它是否对文件进行分段并仅将新数据写入另一个位置(请记住,中间有一些可用空间)?它是否真的只覆盖已更改的部分

有一个很好的理由问:在第一种情况下,如果您不断更新文件,系统可能会变慢。在第二种情况下,它可能会更快,但如果对许多文件执行,它会弄乱文件系统。在第三种情况下,特别是如果您有固态磁盘,一遍又一遍地更新文件的同一位置可能会使磁盘的该部分无用。

实际上,这就是我的问题的来源。我读过那篇文章,为了避免过度使用磁盘扇区,固态磁盘使用不同的技术将数据移动到使用较少的扇区。但是stdio 函数究竟是如何处理这种情况的呢?

提前感谢您的宝贵时间! :D

【问题讨论】:

像 stdio 这样的标准库不关心磁盘扇区。这就是司机的目的。此外,除了写入磁盘之外,还涉及更多内容,因为标准库只是将请求路由到操作系统,操作系统会检查访问权限(如果合适),然后将请求转发给驱动程序。 stdio 尽可能远离光盘。 stdio 甚至根本不知道数据是否已写入磁盘。它只是将其写入标准化流,可以是磁盘、网络或一些 RAM,或其他任何东西。它也可以是垃圾箱(又名 /dev/null):) 另外,当你删除和写入很多时,通常会出现碎片。在这种情况下,文件可能会“散落”在整个磁盘上,这会使访问速度变慢,因为驱动程序必须等待更多扇区被读取。当一个文件被写入一个连续的块中时,驱动程序可以处理它,以便光盘的旋转(如果它旋转)针对访问特定文件进行了优化。 谢谢!这很有帮助!!! :D 顺便问一下,你知道有什么方法(除了在汇编中编写操作系统)我们可以直接访问驱动器吗? 如何编写驱动程序取决于操作系统。但是,大多数驱动程序不再用汇编语言编写。您只需要小的汇编程序部分来执行其他方式不可用的指令,但大部分代码是 C 甚至 C++。对于 Windows,您可以查看可免费下载的 DDK。对于 Linux,源代码仍然可用。 :) 我会用谷歌搜索一些开源驱动程序(如果你走 Windows 路线)并看看它们。你可以看看 ReactOS,它是 Windows OSS 的替代品,并且是二进制兼容的,所以你肯定可以在他们的代码中找到一些东西。 现在我想起来了,您应该能够通过 UNC 路径(在 Windows 中)直接访问驱动器,当然在 Unix 中通过访问 /dev。如果您有适当的权限,您可以编写一个直接访问设备的用户空间应用程序,这样您就可以编写本地文件系统而无需编写完整的驱动程序。 【参考方案1】:

文件系统处理程序对磁盘上的扇区创建一种字典式写入,因此当您更新文件的内容时,文件系统会查找磁盘上的字典,它会告诉它文件在磁盘上的哪个扇区数据位于。然后它会旋转(或等到光盘到达那里)并更新光盘上的相应扇区。

这是简短的版本。

因此,在更新文件的情况下,文件通常不会移动到新位置。当您将新数据写入文件并附加到文件中时,如果数据不适合现有扇区,则会分配额外的扇区并将数据写入那里。

如果您删除文件,通常这些扇区会被标记为空闲并被重复使用。所以只有当你打开一个新文件并重写它时,文件才可能被放在不同的扇区中。

但细节可能会有所不同,具体取决于硬件。 AFAIK 如果您覆盖 CD 上的数据,则数据是新写入的(只要会话未完成),因为一旦写入 CD,您就无法更新 CD 上的数据。

【讨论】:

这意味着它会覆盖旧数据?但对于 SSD 驱动器也是如此吗? 如何写入数据,主要取决于文件系统驱动程序。在 SSD 上使用 FAT 的 AFAIK 并不是一件好事,因为它往往会经常覆盖相同的扇区。因此,更好地分发它的文件系统是更好的选择,但我不确定。【参考方案2】:

您的理解不正确:“请注意,我们不会删除文件中以前存在的任何数据”

如果您在文件中间寻找并开始写入,它将覆盖之前该位置的任何内容。

这如何在幕后完成可能取决于硬盘中的计算机如何实现它。它应该在硬盘之外是不可见的,应该没有关系。

【讨论】:

是的,这就是我们想要做的。根据我的评论,我只是想提一下,我们不会将文件截断为零长度以删除所有数据(例如使用 wb)。 有一种情况很重要:当你想故意覆盖数据时!!! :D 您不能使用 write() 方法缩短文件。您只能更改现有数据或添加到文件末尾。

以上是关于fwite/putc 如何写入磁盘?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 .Net 直接写入磁盘?

如何将 lucene 的 ByteBuffersDirectory 写入/序列化到磁盘?

如何优化mysql写入速

java中如何通过IO流将稀疏数组写入磁盘和从磁盘中读取,整行存,整行取

iPhone:如何在应用程序目录中将图像写入磁盘

R如何在将csv文件写入磁盘之前估计它的大小