15
  • 平台:Debian Wheezy 3.2.0-4-686-pae
  • 编译器:GCC (Debian 4.7.2-5) 4.7.2 (Code::Blocks)

我想将文件从一个位置移动到另一个位置。没有什么比移动到不同的驱动器或不同的文件系统更复杂的了。我知道执行此操作的“标准”方法是简单地复制文件,然后删除原始文件。但我想要某种方式来保留文件的所有权、模式、上次访问/修改等。我假设我必须复制文件,然后编辑新文件的所有权、模式等,但我不知道该怎么做。

4

2 回答 2

30

在 C 中移动文件的常用方法是使用rename(2),但有时会失败。

如果您不能使用rename(2)系统调用(例如因为源和目标在不同的文件系统上),您必须使用stat(2)查询源文件的大小、权限和其他元数据;复制read(2)write(2)(使用几千字节的缓冲区)、open(2)close(2)上的数据循环和使用chmod(2)chown(2)utime(2)的元数据. 您可能还关心使用getxattr(2)setxattr(2)listxattr(2)复制属性。您也可以在某些情况下使用sendfile(2),如评论 大卫·C·兰金

如果源和目标位于不同的文件系统上,则无法使移动原子化并避免竞争条件(因此,如果可能,最好使用rename(2),因为根据其手册页它是原子的)。在移动操作期间始终可以修改源文件(由另一个进程)...

因此,移动文件的一种实用方法是首先尝试执行rename(2),如果失败EXDEV(当oldpathnewpath不在同一个挂载的文件系统上时),那么您需要复制字节和元数据。几个库提供了这样做的函数,例如 Qt QFile::rename

阅读Advanced Linux Programming - 并查看syscalls(2) - 了解更多信息(并尝试使用strace一些mv命令来了解它在做什么)。该书可免费合法下载(因此您可以在网上找到几本)。

/bin/mv命令(参见mv(1) )是自由软件GNU coreutils的一部分。您可以研究它的源代码,或者使用strace(1)来了解该命令的作用(就syscalls(2)而言)。在像sashbusybox这样的一些开源Unix shell中,可能是一个内置的 shell。另请参见path_resolution(7)glob(7) mv

有一些微妙的极端情况(想象另一个进程或 pthread 在同一个文件系统、目录或文件上执行一些文件操作)。阅读一些操作系统教科书了解更多信息。

如果文件名包含奇怪的字符,例如or换行符,或者以首字母. 请参阅errno(3)tab -

于 2013-07-03T05:08:57.470 回答
18

如果文件的原始位置和新位置位于同一文件系统上,则“移动”在概念上与“重命名”相同。

#include <stdio.h>

int rename (const char *oldname, const char *newname)
于 2013-07-03T01:53:03.963 回答