28

我认为这个问题对于 Stack Overflow 来说已经足够技术了,对于Android来说可能过于面向编程。我对 Android(或 Java 或 Linux,视情况而定)如何处理文件很感兴趣,因为我用我的新智能手机做了一些事情,我很想知道它是如何发生的。

我正在通过蓝牙将文件从笔记本电脑传输到我的 Android 手机。我在文件资源管理器中看到了新文件,假设它已完全传输,因此将其/sdcard/bluetooth/sdcard/torrents. 在我这样做之后,我注意到它实际上仍在被转移。令我惊讶的是,它成功完成,通过手机上的通知图标确认,并通过双方的手动 MD5 检查。在大多数系统中,文件移动会导致崩溃。

这次转让成功的原因是什么?我知道,通常,文件路径与文件系统上的文件位置(在本例中为 SD 卡)是分开的。我想蓝牙应用程序已经打开了文件的句柄,当我移动文件时,“打开文件”表被更新为新路径。这个特性在任何 Linux 系统中都普遍存在吗?我可以mv对正在写入的文件执行操作并期望副本 - 在其新位置 - 是正确的吗?

4

1 回答 1

55

当您在同一个文件系统中移动文件时,文件本身(inode)根本不会移动。唯一改变的是该文件系统中的目录条目。mv(在这种情况下调用的系统调用是rename(2)- 检查该页面以获取更多信息和限制。)

当一个进程打开一个文件时,文件名被传递给操作系统以指示哪个文件是指哪个文件,但你得到的文件描述符根本没有链接到那个名字(你不能从中得到一个文件名)——它链接到inode。
由于在重命名文件时(在同一个文件系统中)inode 保持不变,打开它的进程可以愉快地继续读取和写入它——它们没有任何改变,它们的文件描述符仍然有效并指向正确的数据。

如果你删除一个文件,同样的事情。即使文件不再可以通过任何目录条目访问,进程也可以继续从中读取和写入。(这可能会导致令人困惑的情况,即df报告您的磁盘已满,但du表示您使用的空间比df报告的少得多。分配给仍处于打开状态的已删除文件的块在这些进程关闭其文件描述符之前不会被释放。 )

如果mv跨文件系统移动文件,则行为会有所不同,因为 inode 特定于每个文件系统。在这种情况下,mv实际上将复制数据,在目标文件系统上创建一个新的 inode(和目录条目)。复制结束后,旧文件将被取消链接,如果上面没有打开的文件句柄,则将其删除,如上所述。
在您的情况下,如果您跨越了文件系统边界,那么您将在目标中有一个部分文件。并且您的上传过程愉快地写入您无法轻松访问的已删除文件,可能会填满该文件系统,直到上传完成,此时 inode 将被删除。

您可能会发现一些关于Unix 和 Linux的帖子很有趣:

于 2012-08-05T18:47:54.540 回答