【问题标题】:How to make copies of the executable itself in C++?如何在 C++ 中复制可执行文件本身?
【发布时间】:2022-11-27 15:50:13
【问题描述】:

我想多次复制 exe 文件本身。

我尝试了以下代码:

#include <fstream>
#include <string>

int main() {
    std::ifstream from("main.exe", std::ios::binary);
    auto buf { from.rdbuf() };

    for(int x { 0 }; x <= 10; ++x) {
        std::string name { "main" + std::to_string(x) + ".exe" };

        std::ofstream out(name, std::ios::binary);
        out << buf;
        out.close();
    }

    from.close();
    return 0;
}

但它没有像我预期的那样工作(它不会重复复制可执行文件。请参阅以下屏幕截图中的大小列):

我该如何解决这个问题?

【问题讨论】:

  • 这没有解决问题,但无需致电out.close(); 或from.close();。析构函数会这样做。
  • 如果我是治标不治本(我现在没有精力认真分析代码),我会把main 的前两行移到循环内。
  • 声明out &lt;&lt; buf;将提炼来自buf 的所有数据,没有留下任何东西。
  • 您永远不会检查打开文件是否成功。打开后添加if(!from) { std::cout &lt;&lt; std::strerror(errno) &lt;&lt; '\n'; return 1; }。

标签: c++ fstream


【解决方案1】:

从输入文件流缓冲区读取数据。复制文件后,您需要将流重置为开始:

...

for (int x{ 0 }; x <= 10; ++x) {
    std::string name{ "main" + std::to_string(x) + ".exe" };

    std::ofstream out(name, std::ios::binary);
    out << buf;
    out.close();
    from.seekg(0, std::ios::beg); // need to go back to the start here
}

...

不过,您可以简单地使用 std::filesystem 标准库功能:


int main() {
    std::filesystem::path input("main.exe");

    for (int x{ 0 }; x <= 10; ++x) {
        std::filesystem::path outfile("main" + std::to_string(x) + ".exe");

        std::filesystem::copy_file(input, outfile, std::filesystem::copy_options::overwrite_existing);
    }

    return 0;
}

【讨论】:

  • 使用seekg(0, ...) 将导致多次读取文件(每次保存一次)。不是吗?
【解决方案2】:

在第一次迭代期间从输入缓冲区读取所有内容后,输入缓冲区为空。因此,您的后续迭代也将呈现空副本。我建议像这样在循环内移动 from 缓冲区初始化:

#include <fstream>
#include <string>

int main() {

    for (int x{ 0 }; x <= 10; ++x) {
        std::ifstream from("main.exe", std::ios::binary);
        auto buf{ from.rdbuf() };
        std::string name{ "main" + std::to_string(x) + ".exe" };

        std::ofstream out(name, std::ios::binary);
        out << buf;
        out.close();
        from.close();
    }

    
    return 0;
}

这是你应该得到的:

【讨论】:

    【解决方案3】:

    在其他答案中,数据将从文件中读取多次(每次保存一次)。
    如果您在循环内创建一个新的 std::ifstream 对象,就会发生这种情况,如果您使用 seekg 转到流的开头,也会发生这种情况。

    由于磁盘访问相对较慢(与内存访问相比),它会更高效阅读它曾经进入记忆, 然后节省根据需要多次从记忆里.

    下面的代码将文件二进制内容读入std::vector。然后多次写入向量的内容以创建新文件:

    #include <string>
    #include <vector>
    #include <fstream>
    
    int main() {
    
        // Read the entire main.exe file into memory:
        const std::string inFilename{ "main.exe" };
        std::ifstream inFile{ inFilename, std::ios_base::binary };
        std::vector<char> inFileData{ std::istreambuf_iterator<char>(inFile), std::istreambuf_iterator<char>() };
        inFile.close();
    
        // Save it as many times as needed:
        for (int x{ 0 }; x <= 10; ++x) 
        {
            std::string name{ "main" + std::to_string(x) + ".exe" };
            std::ofstream outFile{ name, std::ios::binary };
            outFile.write(inFileData.data(), inFileData.size());
            outFile.close();
        }
    }
    

    【讨论】:

      【解决方案4】:

      第一个副本完成得很完美。我最好的猜测是输入缓冲区之后是空的,所以所有连续的副本都是空的。

      【讨论】:

      • 这可能是一个合理的评论;这不是答案。
      猜你喜欢
      • 2018-05-29
      • 1970-01-01
      • 2010-10-30
      • 2018-04-13
      • 1970-01-01
      相关资源
      最近更新 更多