是否有POSIXfunction来复制文件?

现在看一下OS函数,我发现在POSIX系统上你有C函数调用,如unlink()删除文件, link()创建文件的硬链接, symlink()创建符号文件, rename()移动文件,但是… copy()文件的函数在哪里?

我知道通常的方法是打开源文件,读取其内容,打开目标文件并将其转储到那里。 但是为什么我不能在以前的所有function中找到任何这样的效用函数?

在谈论“复制文件”时,存在两种语义:

  1. 深层复制 – 创建一个新文件,其中包含与该文件关联的所有数据/元数据的副本,但文件系统构建此文件
  2. 浅复制 – 创建新的目录条目/文件, 引用相同的数据 (以及可能的部分或全部元数据)作为源文件

Windows / DOS文件系统传统上没有任何“浅拷贝”机制 – 但UN * X总是以硬链接的forms出现。

因此POSIX / UN * X具有link(2)系统调用 – 以新名称建立对现有“文件数据”的新引用 – 即,执行浅拷贝

只有存在“快速深层复制”机制时,“深度复制”系统调用才有意义 – 例如,在底层文件系统实现类似重复数据删除的操作以进行文件级克隆的情况下。

否则,这样的函数将不得不“降级”(回退)到库实现。

UN * X机制允许作为文件系统特定的东西,因为它是ioctl() ,“I / O可扩展性的厨房接收器”。 有关如何使用此工具(如果可用)复制文件的示例,请参阅此GNU coreutilspost,其中包含在BTRFS上使用文件克隆的增强请求。

鉴于Windows的CopyFile实际上是没有回调的CopyFileEx ,我强烈怀疑它真的是一个系统调用 ; 这是一个实用function。 对于Wine Windows Emulator ,您可以检查kernel32.dll源代码实现,在Wine源代码中查找CopyFileExdlls/kernel32/path.c以获取如何完成此操作的示例。
在Microsoft的许可下不允许反汇编/反编译Windows的实际kernel.dll ,因此我无法合法地断言Windows本身也是如此,即CopyFile是用户域实现, 而不是系统调用

在这里再次比较Windows和UN * X ……并非UN * X libc中的所有内容都是系统调用,这就是UN * X联机帮助页区分第2节(sys调用)和第3节(运行时库接口)的原因。 对于Windows上的kernel.dll中的函数也是如此 – 其中一些是“直接直通”,而另一些则是通过单个系统调用未实现的更复杂的“实用函数”。

我尝试在Linux上的cp命令上运行strace,它实际上打开了两个文件,它从一个文件读取并以32768字节的块写入另一个文件:

 ... stat64("log", {st_mode=S_IFREG|0644, st_size=352, ...}) = 0 stat64("copied", 0xbf99e1c0) = -1 ENOENT (No such file or directory) open("log", O_RDONLY|O_LARGEFILE) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=352, ...}) = 0 open("copied", O_WRONLY|O_CREAT|O_EXCL|O_LARGEFILE, 0644) = 4 fstat64(4, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 read(3, "2012-04-27 22:26:55-0400 [-] Log"..., 32768) = 352 write(4, "2012-04-27 22:26:55-0400 [-] Log"..., 352) = 352 read(3, "", 32768) = 0 close(4) = 0 close(3) = 0 ... 

所以是的,那里没有cp系统调用。 希望它能帮到你。

您无法找到用于复制文件的实用程序function,因为不需要以相同的方式使用它; 它可以用“备件”制造。 像unlink()symlink()函数不能用其他函数构建,而假设的copy_file()等函数可以(所以你必须)。

给定两个打开的文件流, f1用于读取, f2用于写入,则可以使用:

 void fcopy(FILE *f1, FILE *f2) { char buffer[BUFSIZ]; size_t n; while ((n = fread(buffer, sizeof(char), sizeof(buffer), f1)) > 0) { if (fwrite(buffer, sizeof(char), n, f2) != n) err_syserr("write failed\n"); } } 

err_syserr()函数用于错误报告,包括作为参数传递的字符串和errno *隐含的错误消息; 它没有回来。 BUFSIZ定义,但您可以选择使用更大的值。 您可能不希望错误报告,但成功时返回0,任何失败时返回-1。

 int fcopy(FILE *f1, FILE *f2) { char buffer[BUFSIZ]; size_t n; while ((n = fread(buffer, sizeof(char), sizeof(buffer), f1)) > 0) { if (fwrite(buffer, sizeof(char), n, f2) != n) return -1; } return 0; } 

请注意,因为该函数不会打开文件,所以它也不会关闭它们。 例如,这意味着您可以使用它将多个输入文件连接到单个输出文件。 您可以使用包装函数打开文件进行读取,使用另一个文件进行写入。

* 实际上, err_syserr()是一个类似printf()的函数,它接受格式字符串和其他参数,然后按照描述报告错误消息并退出。

POSIX系统不提供Win32中的CopyFile函数之类的系统调用,因此不要浪费时间搜索Copy_file()函数。 如果您不想重新发明轮子,我认为使用fork()创建一个新进程并调用execl()是个好主意。 像这样:

 execl("/bin/cp", "-p", src_file, des_file, (char *)0);