How to create a temporary directory in C++? - 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?

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

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.

Check the mkdtemp function here.

Boost's Filesystem library provides platform-independent directory functions. It will increase your program size a bit, but using Boost is often better (and often easier) than rolling your own.
http://www.boost.org/doc/libs/1_43_0/libs/filesystem/doc/index.htm

There's no standard function to do this, so you'll need to compile different implementations for each platform you target.
On Windows, for example, you should use the temp directory, which can be obtained by a call to GetTempPath().

mkdtemp(char *template)
http://www.cl.cam.ac.uk/cgi-bin/manpage?3+mkdtemp
Creates a temporary directory.

Related

"Permission denied collect2.exe: error: ld returned 1 exit status" Error when using #include<openssl/evp.h> in VSCode

So I installed OpenSSL directly following the instructions in the install.txt file you get when cloning the git repository. It installed it seemingly witout issues and is located in C:/Program Files/OpenSSL and C:/Program Files(x86)/OpenSSL. Inside each of those there are 4 folders: bin, html, include, lib.
In VSCode I'm using the code runner extension with the following command:
g++ -I "C:/Users/Batres/vcpkg/installed/x86-windows/include" "C:/Program Files/OpenSSL/include" simple_functions.cpp -o simple_functions
the "C:/Users/Batres/vcpkg/installed/x86-windows/include" is a different library called XTensor, which works completely fine as I have tested the code without OpenSSL and it outputs the correct results with no problem. This is the code I'm using, although I doubt it's relevant since it seems to be a complier issue.
#include <cmath>
#include <iomanip>
#include <cstddef>
#include "xtensor.hpp"
#include <functional>
#include <string>
#include <typeinfo>
#include <vector>
#include <regex>
#include <array>
#include <algorithm>
#include <openssl/sha.h>
#include <openssl/evp.h>
/*
def hash_string(string):
# Truncating at 16 bytes for cleanliness
hasher = hashlib.sha256(string.encode())
return hasher.hexdigest()[:16]
*/
std::string hash_string(std::string string) {
// Truncating at 16 bytes for cleanliness
std::array<unsigned char, SHA256_DIGEST_LENGTH> hash;
std::array<unsigned char, SHA256_DIGEST_LENGTH>::iterator it;
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
EVP_DigestUpdate(ctx, string.c_str(), string.size());
EVP_DigestFinal_ex(ctx, hash.data(), NULL);
// Convert the hash to a hexadecimal string
std::stringstream ss;
for (it = hash.begin(); it != hash.end(); it++) {
ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(*it);
}
return ss.str().substr(0, 16);
}
int main(){
double a = gen_choose(2,5);
std::string input = "Hello, world!";
std::string output = hash_string(input);
std::cout << std::setprecision(16) << output << std::endl;
return 0;
}
Ignore all the other #includes, they are for different functions that work with no issue. As you can probably see I have some python code commented above my C++ code. Thats simply because it's a function I tried transalting using ChatGPT, but that's not relevant to the error.
This is the line for C++ settings in code-runner.executorMap:
"cpp": "cd $dir && g++ -I \"C:/Users/Batres/vcpkg/installed/x86-windows/include\" \"C:/Program Files/OpenSSL/lib\" $fileName -o $fileNameWithoutExt -lssl && $dir$fileNameWithoutExt"
My compiler is mingw and I'm on Windows 11. I also don't have any antivirus aside from Windows Defender and I've added the library to the exceptions list as well as ld.exe.
I have also tried these commands, all yeilding the same error. I have also tried running all the same commands through a terminal with admin priviliges and it gives the same error. I even copied the folder to a different directory inside my /Documents/ folder and it still didn't help.g++ -I "C:/Users/Batres/vcpkg/installed/x86-windows/include" "C:/Program Files (x86)/OpenSSL/include" simple_functions.cpp -o simple_functions
and
g++ -I "C:/Users/Batres/vcpkg/installed/x86-windows/include" -L "C:/Program Files/OpenSSL/lib" simple_functions.cpp -o simple_functions -lssl
This last one returns a different error. Insted of being acces denied it seems like none of the functions or variables that I call inside my code are recognised, so this is the type of error: undefined reference to 'EVP_MD_CTX_new', or any other functions or variables I call.
The weird thing is that even though it says access denied when compliling, Intellisense can acess the files just fine, I can right click on the functions and "Go to Definition" and it takes me to my C:/Program Files/OpenSSL/include/openssl/ folder.
If anyone knows how to fix the error I would be very thankful.

How do I properly include files from the NVIDIA C++ standard library?

I was trying to use shared pointers in CUDA by using NVIDIA's version of the C++ standard library. So tried to include <cuda/std/detail/libcxx/include/memory>. I got some errors. One of them includes cannot open source file with <__config> and <__functional_base>. Those files were clearly in the directory. It's like visual studios acts like those files don't exist even though they do. Another error I get is linkage specification is incompatible with previous "" with <cmath>.
I did little digging. I found out that cannot open source file is apparent with every non-header file that starts with _ in cuda/std/detail/libcxx/include/. It is like Visual Studio somehow acts like those files don't exist despite being clearly located in the additional include directories. Furthermore, when I type cuda/std/detail/libcxx/include/, IntelliSense won't find these files. If I can get visual studio to recognize those files, I can properly include any files in NVIDIA's version of standard library.
The first thing to understand is that CUDA doesn't have a C++ standard library. What you are referring to is the libcu++, which is an extremely bare bones heterogenous reimplementation of a tiny subset of what is defined in the C++ standard library. You can use whatever is defined in libcu++ (and that is not much, it is a very incomplete implementation) as follows:
Prepend the local path cuda/std/ to whatever standard library header you are using to substitute the import from the native host C++ standard library to libcu++
Change the namespace from std to cuda::std
compile using nvcc
As a simple example:
$ cat atomics.cpp
#include <iostream> // std::cout
#include <cuda/std/atomic> // cuda::std::atomic, cuda::std::atomic_flag, ATOMIC_FLAG_INIT
#include <thread> // std::thread, std::this_thread::yield
#include <vector> // std::vector
cuda::std::atomic<bool> ready (false);
cuda::std::atomic_flag winner = ATOMIC_FLAG_INIT;
void count1m (int id) {
while (!ready) { std::this_thread::yield(); } // wait for the ready signal
for (volatile int i=0; i<1000000; ++i) {} // go!, count to 1 million
if (!winner.test_and_set()) { std::cout << "thread #" << id << " won!\n"; }
};
int main ()
{
std::vector<std::thread> threads;
std::cout << "spawning 10 threads that count to 1 million...\n";
for (int i=1; i<=10; ++i) threads.push_back(std::thread(count1m,i));
ready = true;
for (auto& th : threads) th.join();
return 0;
}
$ nvcc -std=c++11 -o atomics atomics.cpp -lpthread
$ ./atomics
spawning 10 threads that count to 1 million...
thread #6 won!
Note that as per the documentation, there are presently (CUDA 11.2) only implementations of:
<atomic>
<latch>
<barrier>
<semaphore>
<chrono>
<cfloat>
<ratio>
<climits>
<cstdint>
<type_traits>
<tuple>
<functional>
<utility>
<version>
<cassert>
<cstddef>
with complex support coming in the next CUDA release from the looks of things.
You mentioned shared pointers. There is no <memory> implementation at present, so that cannot be made to work.

file systems in C++

I'm working on a project in which I have to do some file handling.
If only someone could tell how to work with file system like
moving, copying, deleting, renaming and checking for the existence of files in Windows.
Check file management functions section on msdn.
For example, to copy a file with WinAPI you can use CopyFile:
#include <windows.h>
#include <iostream>
int main()
{
BOOL ret = CopyFile(TEXT("test.txt"), TEXT("test-copy.txt"), TRUE);
if (ret)
std::cout << "CopyFile failed. GetLastError:" << GetLastError() << std::endl;
}
If your compiler supports you may as well use std::filesystem which is portable (e.g. that code should work equally well on windows and linux):
#include <filesystem>
int main()
{
std::filesystem::copy("test.txt", "test-copy.txt");
}
There is also boost::filesystem that heavily influenced std::filesystem.

Opening a directory in c++

I'm trying to write a program that moves files from one directory to another, so far I have this written.
void file_Move(ifstream in,ofstream out)
{
string name, name2;
int downloads;
cout << "Enter 1 if the file you wish to move is in downloads" << endl;
cin >> downloads;
if (downloads == 1)
{
opendir("F:/Downloads"); //supposed to open the directory so that the user can input the file they wish to be moved.
closedir("F:/Downloads");
}
}
Visual Studio doesn't have the dirent.h library which is necessary for opendir and closedir, so I was wondering if there was a similar or better way of doing what those do.
Your code doesn't make much sense as it stands right now.
On one hand, file_move takes an ifstream and an ofstream, which would imply that you've already found and opened the files you care about. Then it goes on to attempt to search for files...
For the moment, I'm going to assume you need to search for the files you care about. In this case, you probably want to use the filesystem library. With a really up to date compiler, this may be directly in std::. For a slightly older compiler, it may be in std::experimental. For one that's older still (predates the Filesystem TS) you'll probably need to use Boost Filesystem instead.
In any case, code to use this would run something like this:
#include <string>
#include <filesystem>
#include <iostream>
#include <iterator>
#include <algorithm>
void show_files(std::string const & path) {
// change to the std or Boost variant as needed.
namespace fs = std::experimental::filesystem::v1;
fs::path p{ path };
fs::directory_iterator b{ p }, e;
std::transform(b, e,
std::ostream_iterator<std::string>(std::cout, "\n"),
[](fs::path const &p) {
return p.string();
}
);
}
Of course, if you're going to copy files, you probably want to put the file names in a vector (or something on that order) rather than just displaying them--but presumably you know how to do what you want once you have file names to work with.
In any case, to call this you can just pass the path to the directory you care about, such as F:/Downloads:
show_files("f:/Downloads");
Of course, under a system that uses POSIX paths, you'll pass a different input string (e.g., might be something like "/home/some_user/Downloads" instead). Oh, and at least with its usual directory structure, with g++ the header will be experimental/filesystem instead of just filesystem.

Find specific file type in a directory (C++)

I want to make a program that can search through a specific folder on my computer to find certain files. In this case I want it to look for text files. I've heard some sources claim that this can be done using the standard C++ library. If so, how can I go about doing this? I believe the working code should look something like this:
string path = "C:\\MyFolder\\";
while(/*Searching through the directory*/)
{
if (/*File name ends with .txt*/)
{
/*Do something*/
}
}
There's no support for working with directories in the standard library. There's however an effort to incorporate Boost.Filesystem into the C++17 standard. For now, you can just use Boost directly.
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string/predicate.hpp>
int main(int argc, char* argv[])
{
namespace fs = boost::filesystem;
namespace ba = boost::algorithm;
fs::path dir_path(".");
for (const auto& entry : fs::directory_iterator(dir_path)) {
if (fs::is_regular_file(entry)) {
std::string path = entry.path().string();
if (ba::ends_with(path, ".txt")) {
// Do something with entry or just print the path
std::cout << path << std::endl;
}
}
}
}
update:
To compile the snippet, you need to have Boost installed (and compiled, Filesystem is not header-only). Follow the tutorials here. Then make sure to link with boost_filesystem:
g++ -std=c++11 -Wall test.cc -lboost_filesystem && ./a.out
And don't forget to create some .txt files in the same directory so that the program has something to chew on.