c++ - Gnuplot 和 std::filesystem::remove

标签 c++ ubuntu gcc gnuplot std-filesystem

我正在尝试从 C++ 应用程序 gcc 版本 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) 使用 gnuplot。我遇到了有关打印到文件的奇怪行为。

所以,可重现的例子是:

#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不删除文件,返回 false 并且(因此)打印关于成功的神秘消息,错误代码为 0。 在 std::filesystem::remove 之前移动 pclose(gp); 行解决了这个问题,因此看起来 gnuplot 确实保存了该文件。同样奇怪的是,如果我手动执行相同的操作,我的意思是,我启动 gnuplot,发出相同的命令,但没有退出,我可以使用 unlink/tmp/1.png 删除文件>。我知道 gnuplot 的 set outputunset output 要求,并尝试了这两种变体。

为什么 std::filesystem::remove 行为如此奇怪?

最佳答案

Why the std::filesystem::remove acts this strange?

您似乎误解了std::filesystem::remove() 的返回值和错误代码(代码中的ec)。如果您尝试删除的文件不存在(ec 将为零),该函数不会引发错误。只有没有 error_code& 的函数在您尝试删除的文件不存在时返回 false,在存在时返回 true。参见 cppreference.comstd::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() 将返回 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(),仍然有可能在 gnuplot 命令完成之前调用 std::filesystem::remove(),因为popen 的异步性质。

为确保文件在 gnuplot 进程完成后被删除, 您将需要可以同步 gnuplot 和 c++ 程序的实现(或包装库)。

关于c++ - Gnuplot 和 std::filesystem::remove,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64926838/

相关文章:

c++ - 为什么不允许使用 `make_unique<T[N]>`?

c++ - 在 Xcode : -libmysqlcppconn library not found 中使用 MySQL Connector/C++

c++ - 我在计算 4 个值的方差时的错误在哪里?

java - 如何在 Unity 中设置 Java 应用程序名称?

c - gdb 在 Centos 上找不到调试信息

c++ - 从 std::string 到 std::vector<bool> 的快速转换

ubuntu - s3fs:AWS 消息:访问被拒绝 Ubuntu 11.10

linux - startx/bin/bash 全屏显示,无需桌面

c - 在 ubuntu 上使用 berkeleydb - 找不到 db 库

c - 体系结构 x86_64 的 undefined symbol 在 C 中意味着什么?