现在通过一些操作系统函数,我发现在POSIX系统上你有像unlink()
这样的C函数调用来删除文件,link()
来创建文件的硬链接,symlink()
来创建符号文件,rename()
移动文件,但是...... copy()
文件的功能在哪里?
我知道通常的方法是打开源文件,读取其内容,打开目标文件并将其转储到那里。但是为什么我不能找到所有以前的实用功能呢?
答案 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)
在谈论“复制文件”时,存在两种语义:
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);