Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a temporary directory in C++?

I'm writing a function in C++ which creates a temporary directory. Such function should be as most portable as possible, e.g. it should work under linux, mac and win32 environments. How do I achieve that?

like image 758
Igor Gatis Avatar asked Jul 31 '10 22:07

Igor Gatis


People also ask

What is the C :\ TEMP folder?

A folder (directory) used to hold non-permanent files. The folder is easily created and deleted by the user. Windows creates a temporary folder in c:\windows\temp as a common folder for temporary use by applications. See temporary file and temporary Internet files.

Which command is used to create a temporary directory?

Use mktemp -d . It creates a temporary directory with a random name and makes sure that file doesn't already exist.

How do I create a tmp file?

To create and use a temporary fileThe application opens the user-provided source text file by using CreateFile. The application retrieves a temporary file path and file name by using the GetTempPath and GetTempFileName functions, and then uses CreateFile to create the temporary file.

How do I create a TEMP folder in C++?

You have to query its value first. Use std::getenv("TEMP") or GetEnvironmentVariable("TEMP") to get the resolved temp path, then append your filename to the end of that path, and then pass that complete path to ofstream . .


2 Answers

C++17 std::filesystem::temp_directory_path + random number generation

Here is a pure C++17 solution that might be reliable: no Boost or other external libraries and no mkdtemp which is POSIX.

We just loop over random numbers until we are able to create a directory that did not exist before inside std::filesystem::temp_directory_path (/tmp in Ubuntu 18.04).

We can then explicitly remove the created directory with std::filesystem::remove_all after we are done with it.

I'm not sure that the C++ standard guarantees this, but is extremely likely that std::filesystem::temp_directory_path calls mkdir, which atomically tries to create the directory and if it can't fails with EEXIST, so I don't think there can be race conditions across parallel callers.

main.cpp

#include <exception>
#include <fstream>
#include <iostream>
#include <random>
#include <sstream>

#include <filesystem>

std::filesystem::path create_temporary_directory(
      unsigned long long max_tries = 1000) {
    auto tmp_dir = std::filesystem::temp_directory_path();
    unsigned long long i = 0;
    std::random_device dev;
    std::mt19937 prng(dev());
    std::uniform_int_distribution<uint64_t> rand(0);
    std::filesystem::path path;
    while (true) {
        std::stringstream ss;
        ss << std::hex << rand(prng);
        path = tmp_dir / ss.str();
        // true if the directory was created.
        if (std::filesystem::create_directory(path)) {
            break;
        }
        if (i == max_tries) {
            throw std::runtime_error("could not find non-existing directory");
        }
        i++;
    }
    return path;
}

int main() {
    auto tmpdir = create_temporary_directory();
    std::cout << "create_temporary_directory() = "
              << tmpdir
              << std::endl;

    // Use our temporary directory: create a file
    // in it and write to it.
    std::ofstream ofs(tmpdir / "myfile");
    ofs << "asdf\nqwer\n";
    ofs.close();

    // Remove the directory and its contents.
    std::filesystem::remove_all(tmpdir);
}

GitHub upstream.

Compile and run:

g++-8 -std=c++17 -Wall -Wextra -pedantic -o main.out main.cpp -lstdc++fs
./main.out

Sample output:

_directory.out
temp_directory_path() = "/tmp"
create_temporary_directory() = "/tmp/106adc08ff89874c"

For files, see: How to create a temporary text file in C++? Files are a bit different because open in Linux has the O_TMPFILE, which creates an anonymous inode that automatically disappears on close, so dedicated temporary file APIs can be more efficient by using that. There is no analogous flag for mkdir however, so this solution might be optimal.

Tested in Ubuntu 18.04.


Version 3 of Boost Filesystem Library provides function unique_path() for generating a path name suitable for creating a temporary file or directory.

using namespace boost::filesystem;

path ph = temp_directory_path() / unique_path();
create_directories(ph);
like image 30
Seppo Enarvi Avatar answered Sep 24 '22 15:09

Seppo Enarvi