是否有POSIX功能来复制文件?

时间:2013-07-16 00:51:42

标签: c posix

现在通过一些操作系统函数,我发现在POSIX系统上你有像unlink()这样的C函数调用来删除文件,link()来创建文件的硬链接,symlink()来创建符号文件,rename()移动文件,但是...... copy()文件的功能在哪里?

我知道通常的方法是打开源文件,读取其内容,打开目标文件并将其转储到那里。但是为什么我不能找到所有以前的实用功能呢?

4 个答案:

答案 0 :(得分:14)

我尝试在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系统调用。希望它可以帮到你。

答案 1 :(得分:14)

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

  1. Deep Copy - 创建一个新文件,其中包含与该文件关联的所有数据/元数据的副本,但文件系统构建此
  2. 浅拷贝 - 创建新的目录条目/文件引用相同的数据(以及可能的部分或全部元数据)作为源文件
  3. Windows / DOS文件系统传统上没有任何“浅层复制”机制 - 但UN * X总是以硬链接的形式出现。

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

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

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

    UN * X机制允许某些特定于文件系统的内容,因为它是ioctl(),即“I / O可扩展性的厨房接收器”。有关如何使用此工具(如果可用)复制文件的示例,请参阅带有增强请求的this GNU coreutils post以在BTRFS上使用文件克隆。

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

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

答案 2 :(得分:1)

您无法找到用于复制文件的实用程序功能,因为不需要以相同的方式使用它;它可以用“备件”建造。像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中定义了<stdio.h>,但您可以选择使用更大的值。您可能不希望错误报告,但成功时返回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()的函数,它接受格式字符串和其他参数,然后按照描述报告错误消息并退出。

答案 3 :(得分:1)

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

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