当其他进程(它来自我在我的 c++ 代码中使用 <file.txt>
调用的另一个程序)完成使用它时,我需要删除一个文件(假设它被命名为 system("anotherProgram <file.txt>")
)。
我的程序生成 <file.txt>
,将其传递给外部应用程序。
该应用程序将其步骤写入日志文件,并且该应用程序所有者说在日志文件中打印了一些消息(例如 'aaa'
)后应用程序不需要该文件。
我想外部应用程序只是解析 <file.txt>
完成后打印消息 'aaa'
在日志中。所以,我相信在那之后,删除 <file.txt>
应该是安全的。在我的代码中。
因此,在我的代码中,我正在检查日志文件,当我看到消息 'aaa'
时,我让我的进程休眠 1000 毫秒,然后删除文件。
但在某些情况下,我仍然从该外部应用程序中收到错误,它无法找到 <file.txt>
。文件,所以我猜即使在消息 'aaa'
之后打印在日志中,应用程序仍然尝试使用 <file.txt>
.
我想知道我在这里是否做错了什么。
PS:如果我要睡更长时间(比如 10000 毫秒),我不会遇到这个问题。
最佳答案
明智的做法是通过文件描述符(通常是标准输入)传递文件。
(大多数程序都支持从标准输入读取它们的输入,但如果那个特定的不支持,您仍然可以使用 /proc/self/fd/N
作为文件描述符 N
。)
而不是使用 system()
,你 fork 一个子进程,并让它执行所需的二进制或 shell 命令。我已经展示了一个合适的函数here .
在父进程中,您只需使用 /proc/self/fd/N
对于文件名,并且在执行子进程之前不要关闭文件。您可以取消链接(删除)该文件,因为只要至少有一个进程将其打开,底层 inode(文件元数据和内容)就可以访问。
所以,这是我将使用的方案:
O_CREAT | O_RDWR
或 O_CREAT | O_EXCL | O_RDWR
,或者如果使用 stdio,则 w
或 w+
)。int fd = dup(fileno(handle));
fclose(handle);
否则,我们将假设 fd
是目标文件的文件描述符。lseek(newfd, 0, SEEK_SET);
所以描述符所指描述的文件位置在文件的开头。snprintf(buffer, sizeof buffer, "/proc/self/fd/%d", fd);
打印文件描述符(在子进程中)的路径到(char *)0
作为最终参数。使用前面提到的 buffer
为文件名。pid = run(binary, argarray);
, 其中 argarray
是前面提到的字符串数组,binary
是要运行的二进制文件的名称(如果在以 PATH
命名的目录中),或其完整路径。 (如果它包含斜线,则解释为绝对或相对路径;如果不包含,则使用 PATH 环境变量中指定的目录。)pid == -1
,该命令无法执行;原因在strerror(errno)
.否则,命令将同时运行。reap(pid, NULL)
, 或 reap(pid, &status)
如果您想了解其退出的详细信息,请查看 int status
(但请记住使用 WIFEXITED(status)
、 WEXITSTATUS(status)
等,如 man 2 waitpid 中所述。由于文件的自动删除是预先处理的,如果父进程之后无事可做,而不是派生一个子进程,您可以简单地用新进程替换当前进程,只使用
execv(binary, argarray)
或 execvp(binary, argarray)
,取决于是否 binary
是要执行的程序二进制/脚本的路径或名称。
关于c++ - 在删除文件之前检查文件是否仍在被另一个进程使用(c、c++、linux),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63299821/