Gnuplot 和 std::filesystem::remove
Gnuplot and std::filesystem::remove
我正在尝试使用来自 C++ 应用程序的 gnuplot,gcc 版本 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)。我遇到了有关打印到文件的奇怪行为。
所以,可重现的例子是:
#include <iostream>
#include <filesystem>
int main()
{
// whatever valid filename
std::string name1 = "/tmp/1.png";
// open gnuplot pipe
auto gp = popen("gnuplot", "w");
// plot sin(x) to file. Note "unset output" in the end.
std::string cmd="set term png\nset output '"+name1+"'\nplot sin(x)\nunset output\n";
// send the command to gnuplot
fwrite(cmd.c_str(), sizeof(char), cmd.length(), gp);
std::error_code ec;
// removing the file
if (!std::filesystem::remove(name1, ec))
std::cout<<"unsuccesfully: "<<ec.value()<<"\s"<<ec.message()<<"\n";
pclose(gp);
return 0;
}
输出是(很奇怪):
unsuccesfully: 0 Success
发生了什么:gnuplot 成功地将有效的 png 文件写入所需的目标。但是,std::filesystem::remove 不会删除文件,returns false
并且(因此)打印关于成功的神秘消息,错误代码为 0。
在 std::filesystem::remove
之前移动 pclose(gp);
行解决了问题,因此看起来 gnuplot 确实保存了该文件。同样奇怪的是,如果我手动执行相同的操作,我的意思是,我启动 gnuplot,发出相同的命令,而不是退出,我能够使用 unlink /tmp/1.png
删除文件。我知道 gnuplot 的 set output
或 unset output
要求,并尝试了两种变体。
为什么 std::filesystem::remove
行为如此奇怪?
Why the std::filesystem::remove acts this strange?
您似乎误解了 return 值和 std::filesystem::remove()
的错误代码(您代码中的 ec
)。如果您尝试删除的文件不存在(ec
将为零),该函数不会引发错误。如果您要删除的文件不存在,只有没有 error_code&
returns false
的函数,如果存在,则只有 true
。请参阅 cppreference.com 上 std::filesystem::remove()
的描述。
Effects: the file or empty directory identified by the path p is deleted as if by the POSIX remove. Symlinks are not followed (symlink is removed, not its target).
Returns: true
if the file was deleted, false
if it did not exist. The overload that takes error_code&
argument returns false
on errors.
由于没有出现错误,因为没有要删除的文件,您代码中的 ec.value()
将 return 0
,表示成功完成。
有点像UNIX命令的行为'rm -f'。
您可以通过将以下代码插入代码来检查 std::filesyste::remove()
的行为。
std::error_code ec;
int retval = std::filesystem::remove(name1, ec);
if ( ! ec ) { // Success
std::cout<<"successful: \n";
if ( retval ) {
std::cout<<"file existed and removed\n";
}
else {
std::cout<<"file didn't exist\n";
}
}
else { // Error
std::cout<<"unsuccessful: "<<ec.value()<<" "<<ec.message()<<"\n";
}
加法
之所以pclose()
的位置改变结果是因为popen()
打开的流被缓冲了
当调用std::filesystem::remove()
时,fwrite()
写的命令由于缓冲还没有被gnuplot接收。因此,在这一步中,还没有创建文件“/tmp/1.png”。
然后,当 pclose()
被调用时,gnuplot 接收命令,文件“/tmp/1.png”由 gnuplot 创建。您查看的文件是调用 std::filesystem::remove()
.
后创建的文件
您可以使用函数 fflush()
显式刷新缓冲区。但是,即使您使用 fflush()
,由于 popen 的异步特性,仍然有可能在 gnuplot 命令完成之前调用 std::filesystem::remove()
。
为确保在 gnuplot 进程完成后删除文件,
您将需要可以同步 gnuplot 和 c++ 程序的实现(或包装库)。
我正在尝试使用来自 C++ 应用程序的 gnuplot,gcc 版本 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)。我遇到了有关打印到文件的奇怪行为。
所以,可重现的例子是:
#include <iostream>
#include <filesystem>
int main()
{
// whatever valid filename
std::string name1 = "/tmp/1.png";
// open gnuplot pipe
auto gp = popen("gnuplot", "w");
// plot sin(x) to file. Note "unset output" in the end.
std::string cmd="set term png\nset output '"+name1+"'\nplot sin(x)\nunset output\n";
// send the command to gnuplot
fwrite(cmd.c_str(), sizeof(char), cmd.length(), gp);
std::error_code ec;
// removing the file
if (!std::filesystem::remove(name1, ec))
std::cout<<"unsuccesfully: "<<ec.value()<<"\s"<<ec.message()<<"\n";
pclose(gp);
return 0;
}
输出是(很奇怪):
unsuccesfully: 0 Success
发生了什么:gnuplot 成功地将有效的 png 文件写入所需的目标。但是,std::filesystem::remove 不会删除文件,returns false
并且(因此)打印关于成功的神秘消息,错误代码为 0。
在 std::filesystem::remove
之前移动 pclose(gp);
行解决了问题,因此看起来 gnuplot 确实保存了该文件。同样奇怪的是,如果我手动执行相同的操作,我的意思是,我启动 gnuplot,发出相同的命令,而不是退出,我能够使用 unlink /tmp/1.png
删除文件。我知道 gnuplot 的 set output
或 unset output
要求,并尝试了两种变体。
为什么 std::filesystem::remove
行为如此奇怪?
Why the std::filesystem::remove acts this strange?
您似乎误解了 return 值和 std::filesystem::remove()
的错误代码(您代码中的 ec
)。如果您尝试删除的文件不存在(ec
将为零),该函数不会引发错误。如果您要删除的文件不存在,只有没有 error_code&
returns false
的函数,如果存在,则只有 true
。请参阅 cppreference.com 上 std::filesystem::remove()
的描述。
Effects: the file or empty directory identified by the path p is deleted as if by the POSIX remove. Symlinks are not followed (symlink is removed, not its target).
Returns:
true
if the file was deleted,false
if it did not exist. The overload that takeserror_code&
argument returnsfalse
on errors.
由于没有出现错误,因为没有要删除的文件,您代码中的 ec.value()
将 return 0
,表示成功完成。
有点像UNIX命令的行为'rm -f'。
您可以通过将以下代码插入代码来检查 std::filesyste::remove()
的行为。
std::error_code ec;
int retval = std::filesystem::remove(name1, ec);
if ( ! ec ) { // Success
std::cout<<"successful: \n";
if ( retval ) {
std::cout<<"file existed and removed\n";
}
else {
std::cout<<"file didn't exist\n";
}
}
else { // Error
std::cout<<"unsuccessful: "<<ec.value()<<" "<<ec.message()<<"\n";
}
加法
之所以pclose()
的位置改变结果是因为popen()
打开的流被缓冲了
当调用std::filesystem::remove()
时,fwrite()
写的命令由于缓冲还没有被gnuplot接收。因此,在这一步中,还没有创建文件“/tmp/1.png”。
然后,当 pclose()
被调用时,gnuplot 接收命令,文件“/tmp/1.png”由 gnuplot 创建。您查看的文件是调用 std::filesystem::remove()
.
您可以使用函数 fflush()
显式刷新缓冲区。但是,即使您使用 fflush()
,由于 popen 的异步特性,仍然有可能在 gnuplot 命令完成之前调用 std::filesystem::remove()
。
为确保在 gnuplot 进程完成后删除文件, 您将需要可以同步 gnuplot 和 c++ 程序的实现(或包装库)。