How to make copies of the executable itself in C++?

Viewed 89

I want to make copies of the exe file itself multiple times.

I tried the following code:

#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;
}

But it doesn't work as I expected (It does not copy the executable repeatedly. See the size column in the following screenshot):

The executables not completely copied

Please help me to solve this problem.
Thanks.

4 Answers

Reading from the input file stream buffer consumes the data. You need to reset the stream to the start after copying the file:

...

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
}

...

You could simply use the std::filesystem standard library functionality for this though:


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;
}

After you read all of the contents from the input buffer during your first iteration, your input buffer is empty. Thus, your subsequent iterations will also render empty copies. I suggest moving the from buffer initialization inside the loop like so:

#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;
}

Here's what you should get: enter image description here

In the other answers the data will be read from the file multiple times (once per save).
This will happen if you create a new std::ifstream object inside the loop, and also happen if you use seekg to go to the beginning of the stream.

Since disk access is relatively slow (when compared to memory access), it will more efficient to read it once into memory, then save as many times as needed from memory.

The code below reads the file binary content into a std::vector. Then write the content of the vector multiple times to create the new files:

#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();
    }
}

The first copy is done perfectly. My best guess is that the input buffer is empty afterwards, so all consecutive copies are empty.

Related