如何知道文件是否正在被复制?

发布于 2024-11-07 06:07:40 字数 110 浏览 1 评论 0原文

我目前正在尝试检查文件从一个目录到另一个目录的复制是否完成。 我想知道目标文件是否仍在复制。

所以我想获取此文件上打开的文件描述符的数量。 我使用 C 语言,但没有真正找到解决该问题的方法。

I am currently trying to check wether the copy of a file from a directory to another is done.
I would like to know if the target file is still being copied.

So I would like to get the number of file descriptors openned on this file.
I use C langage and don't really find a way to resolve that problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

篱下浅笙歌 2024-11-14 06:07:41

如果您能够打开文件进行写入,则操作系统很可能已完成复制并释放了其锁定。然而,不同的操作系统对此的行为可能有所不同。

另一种方法是打开源文件和目标文件进行读取并比较它们的大小。如果它们大小相同,则副本很可能已完成。您可以使用 fseek()ftell() 来确定 C 中文件的大小:

fseek(fp, 0L, SEEK_END);
sz = ftell(fp);

If you're able to open the file for writing, there's a good chance that the OS has finished the copy and has released its lock on it. Different operating systems may behave differently for this, however.

Another approach is to open both the source and destination files for reading and compare their sizes. If they're of identical size, the copy has very likely finished. You can use fseek() and ftell() to determine the size of a file in C:

fseek(fp, 0L, SEEK_END);
sz = ftell(fp);
以往的大感动 2024-11-14 06:07:41

在 Linux 中,尝试使用 lsof 命令,该命令会列出系统上所有打开的文件。

编辑1:唯一想到的C语言功能是fstat函数。您可以将其与结构体的 st_mtime (上次修改时间)字段一起使用 - 一旦该值停止更改(例如 10 秒的时间),那么您可以假设文件复制操作已经停止了。

编辑2:另外,在Linux上,您可以遍历 /proc/[pid]/fd查看哪些文件已打开。里面的文件有符号链接,但是C的readlink()函数可以告诉你它的路径,这样你就可以看到它是否仍然打开。使用 getpid(),您将知道程序的进程 ID(如果您正在程序内进行文件复制),从而知道在 /proc 中查找何处。

In linux, try the lsof command, which lists all of the open files on your system.

edit 1: The only C language feature that comes to mind is the fstat function. You might be able to use that with the struct's st_mtime (last modification time) field - once that value stops changing (for, say, a period of 10 seconds), then you could assume that file copy operation has stopped.

edit 2: also, on linux, you could traverse /proc/[pid]/fd to see which files are open. The files in there are symlinks, but C's readlink() function could tell you its path, so you could see whether it is still open. Using getpid(), you would know the process ID of your program (if you are doing a file copy from within your program) to know where to look in /proc.

可是我不能没有你 2024-11-14 06:07:41

我认为您的基本错误是尝试将 C 程序与不用于同步的 shell 工具/外部程序同步。如果您对执行复制的程序/脚本有一定程度的控制,则应该修改它以对目标文件执行某种类型的建议锁定(最好是基于 fcntl 的)。然后你的其他程序可以简单地阻止获取锁。

如果您对执行复制的程序没有任何控制权,唯一的解决方案取决于不可移植的 hack,例如 lsof 或 Linux inotify API。

I think your basic mistake is trying to synchronize a C program with a shell tool/external program that's not intended for synchronization. If you have some degree of control over the program/script doing the copying, you should modify it to perform advisory locking of some sort (preferably fcntl-based) on the target file. Then your other program can simply block on acquiring the lock.

If you don't have any control over the program performing the copy, the only solutions depend on non-portable hacks like lsof or Linux inotify API.

伴梦长久 2024-11-14 06:07:41

(这个答案做出了一个很大很大的假设,即这将在 Linux 上运行。)

lsof 的 C 源代码是一个工具,它告诉哪些程序当前拥有特定文件的打开文件描述符。 免费提供。然而,只是警告你,我无法理解它的任何意义。有提到读取内核内存,所以对我来说,这要么是巫术,要么是黑魔法。

也就是说,没有什么可以阻止您通过自己的程序运行 lsof。从您自己的程序运行第三方程序通常是您出于多种原因而试图避免的事情,例如安全性(如果流氓用户将 lsof 更改为恶意程序,它将以您的程序的权限运行,潜在的灾难性后果),但是检查lsof源代码,我得出的结论是没有公共API来确定哪个程序打开了哪个文件。如果您不害怕人们更改 /usr/sbin 中的程序,您可以考虑这样做。

int isOpen(const char* file)
{
    char* command;
    // BE AWARE THAT THIS WILL NOT WORK IF THE FILE NAME CONTAINS A DOUBLE QUOTE
    // OR IF IT CAN SOMEHOW BE ALTERED THROUGH SHELL EXPANSION
    // you should either try to fix it yourself, or use a function of the `exec`
    // family that won't trigger shell expansion.
    // It would be an EXTREMELY BAD idea to call `lsof` without an absolute path
    // since it could result in another program being run. If this is not where
    // `lsof` resides on your system, change it to the appropriate absolute path.
    asprintf(&command, "/usr/sbin/lsof \"%s\"", file);
    int result = system(command);

    free(command);
    return result;
}

如果您还需要知道哪个程序打开了您的文件(大概是 cp?),您可以使用 popen 读取 lsof 的输出类似的时尚。 popen 描述符的行为类似于 fopen 描述符,因此您所需要做的就是fread 它们并查看是否可以找到程序的名称。在我的机器上,lsof 输出如下所示:

$ lsof document.pdf 
COMMAND PID  USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
SomeApp 873 felix  txt    REG   14,3   303260 5165763 document.pdf

(This answer makes the big, big assumption that this will be running on Linux.)

The C source code of lsof, a tool that tells which programs currently have an open file descriptor to a specific file, is freely available. However, just to warn you, I couldn't make any sense out of it. There are references to reading kernel memory, so to me it's either voodoo or black magic.

That said, nothing prevents you from running lsof through your own program. Running third-party programs from your own program is normally something you try to avoid for several reasons, like security (if a rogue user changes lsof for a malicious program, it will run with your program's privileges, with potentially catastrophic consequences) but inspecting the lsof source code, I came to the conclusion that there's no public API to determine which program has which file open. If you're not afraid of people changing programs in /usr/sbin, you might consider this.

int isOpen(const char* file)
{
    char* command;
    // BE AWARE THAT THIS WILL NOT WORK IF THE FILE NAME CONTAINS A DOUBLE QUOTE
    // OR IF IT CAN SOMEHOW BE ALTERED THROUGH SHELL EXPANSION
    // you should either try to fix it yourself, or use a function of the `exec`
    // family that won't trigger shell expansion.
    // It would be an EXTREMELY BAD idea to call `lsof` without an absolute path
    // since it could result in another program being run. If this is not where
    // `lsof` resides on your system, change it to the appropriate absolute path.
    asprintf(&command, "/usr/sbin/lsof \"%s\"", file);
    int result = system(command);

    free(command);
    return result;
}

If you also need to know which program has your file open (presumably cp?), you can use popen to read the output of lsof in a similar fashion. popen descriptors behave like fopen descriptors, so all you need to do is fread them and see if you can find your program's name. On my machine, lsof output looks like this:

$ lsof document.pdf 
COMMAND PID  USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
SomeApp 873 felix  txt    REG   14,3   303260 5165763 document.pdf
你是暖光i 2024-11-14 06:07:41

正如 poundifdef 提到的,fstat() 函数可以为您提供当前的修改时间。但 fstat 还可以提供文件的大小。

回到 C 的昏暗黑暗时代,当我监视由各种程序复制的文件时,我无法控制我总是:

  1. 等到目标文件大小 >= 源大小,并且
  2. 等待直到目标修改时间比当前时间早至少 N 秒。 N 是一个数字,例如 5,如果经验表明有必要,则设置得更大。是的,5秒看起来有些极端,但它是安全的。

如果您不知道目标文件是什么,那么您唯一真正的选择是#2,但使用较大的 N 以允许最坏情况下的网络和本地 CPU 延迟,同时具有良好的安全系数。

As poundifdef mentioned, the fstat() function can give you the current modification time. But fstat also gives you the size of the file.

Back in the dim dark ages of C when I was monitoring files being copied by various programs I had no control over I always:

  1. Waited until the target file size was >= the source size, and
  2. Waited until the target modification time was at least N seconds older than the current time. N being a number such a 5, and set larger if experience showed that was necessary. Yes 5 seconds seems extreme, but it is safe.

If you don't know what the target file is then the only real choice you have is #2, but user a larger N to allow for the worse case network and local CPU delays, with a healthy safety factor.

稍尽春風 2024-11-14 06:07:41

使用 boost libs 将解决该问题

boost::filesystem::fstream fileStream(filePath, std::ios_base::in | std::ios_base::binary);

if(fileStream.is_open())
    //not getting copied
else
    //Wait, the file is getting copied

using boost libs will solve the issue

boost::filesystem::fstream fileStream(filePath, std::ios_base::in | std::ios_base::binary);

if(fileStream.is_open())
    //not getting copied
else
    //Wait, the file is getting copied
阳光的暖冬 2024-11-14 06:07:40

如果您可以控制它,我建议在执行复制的程序上使用复制移动习惯用法:

cp file1 otherdir/.file1.tmp
mv otherdir/.file1.tmp otherdir/file1

mv 只是更改一些文件系统条目,并且是原子的且速度非常快与副本相比。

If you have control of it, I would recommend using the copy-move idiom on the program doing the copying:

cp file1 otherdir/.file1.tmp
mv otherdir/.file1.tmp otherdir/file1

The mv just changes some filesystem entries and is atomic and very fast compared to the copy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文