一尘不染

为什么在写入文件时可以在Linux中成功移动文件?

java

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

我正在通过蓝牙将文件从笔记本电脑传输到Android手机。我在文件浏览器中看到了新文件,并假设它已完全传输,因此将其从/sdcard/bluetooth移到/sdcard/torrents。完成此操作后,我发现它实际上仍在转移。令我惊讶的是,它成功完成了,并通过电话上的通知图标进行确认,并通过双方的手动MD5检查。在大多数系统中,文件移动会导致崩溃。

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


阅读 446

收藏
2020-12-03

共1个答案

一尘不染

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

当进程打开文件时,文件名将传递到操作系统以指示文件的含义,但是您返回的文件描述符根本没有链接到该名称(您无法从文件名中获取文件名)–它链接到索引节点。
由于在重命名文件时(在同一文件系统内)索引节点保持不变,因此打开该索引的进程可以很高兴地继续对其进行读取和写入操作-
对它们没有任何更改,它们的文件描述符仍然有效并指向正确的数据。

如果删除文件,也是一样。即使文件无法通过任何目录条目访问,进程也可以继续对其进行读写。(这可能会导致令人困惑的情况,即df报告磁盘已满,但du表示您使用的df报告空间要少得多。分配给仍打开的已删除文件的块只有在这些进程关闭其文件描述符后才会释放。

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

您会在Unix和Linux上发现一些有趣的帖子:

2020-12-03