36

I'm trying to create a temporary text file in C++ and then delete it at the end of the program. I haven't had much luck with Google.

Could you tell me which functions to use?


The answers below tell me how to create a temp file. What if I just want to create a file (tmp.txt) and then delete it? How would I do that?

3

9 Answers 9

30

Here's a complete example:

#include <unistd.h> int main(void) { char filename[] = "/tmp/mytemp.XXXXXX"; // template for our file. int fd = mkstemp(filename); // Creates and opens a new temp file r/w. // Xs are replaced with a unique number. if (fd == -1) return 1; // Check we managed to open the file. write(fd, "abc", 4); // note 4 bytes total: abc terminating '\0' /* ... do whatever else you want. ... */ close(fd); unlink(filename); // Delete the temporary file. } 

If you know the name of the file you want to create (and are sure it won't already exist) then you can obviously just use open to open the file.

tmpnam and tmpfile should probably be avoided as they can suffer from race conditions - see man tmpfile(3) for the details.

Sign up to request clarification or add additional context in comments.

3 Comments

The Linux man page for mkstemp(3) says that the last 6 characters in filename must be XXXXXX. See kernel.org/doc/man-pages/online/pages/man3/mkstemp.3.html
Hmm, the OS X manpage for mkstemp says you can have a variable number of XXXs. however in the interests of clarity (and 'cos most people are probably using Linux) I've changed the above example.
Actually it's mktemp and tmpnam that suffer from the race conditions you mention, not tmpfile. tmpfile returns the a C file handle, so you won't get a C++ stream, but you don't get a race condition either. I think the man pages you want to reference above are for tmpname(3) kernel.org/doc/man-pages/online/pages/man3/tmpnam.3.html and mktemp kernel.org/doc/man-pages/online/pages/man3/mktemp.3.html
26

Maybe this will help

FILE * tmpfile ( void ); 

http://www.cplusplus.com/reference/clibrary/cstdio/tmpfile/

Open a temporary file

Creates a temporary binary file, open for update (wb+ mode -- see fopen for details). The filename is guaranteed to be different from any other existing file. The temporary file created is automatically deleted when the stream is closed (fclose) or when the program terminates normally.

See also

char * tmpnam ( char * str ); 

Generate temporary filename

A string containing a filename different from any existing file is generated. This string can be used to create a temporary file without overwriting any other existing file.

http://www.cplusplus.com/reference/clibrary/cstdio/tmpnam/

7 Comments

It is worth mentioning that there might be issues with tmpfile() and tmpnam() in some contexts e.g., codeproject.com/KB/web-security/TemporaryFileSecurity.aspx
Tmpfile, of course, has the problem of returning a C file handle, not a c++ stream.
@rlbond: Indeed, thats why I included tmpnam.
it's very important to note that tmpnam() is not to be used. its man page says: "Never use this function. Use mkstemp(3) or tmpfile(3) instead."
Where exactly is the temporary file created?
|
7

On Linux (starting with kernel 3.11), there's flag to open(2) O_TMPFILE that creates a temporary file that doesn't have a name (i.e. it doesn't show up in the filesystem). This has a few interesting features:

  • No worries about unique names, it's just an inode, there is no name.
  • No race conditions during creation (e.g. symlink attacks).
  • No stray files if your app crashes, it's always automatically deleted.

1 Comment

Minimal runnable example: stackoverflow.com/questions/4508998/… I wonder if glibc can use that to implement tmpfile, but lazy to check now.
6

This may be a little off-topic because the author wanted to create a tmp.txt and delete it after using it, but that is trivial - you can simple open() it and delete it (using boost::filesystem of course).

mkstemp() is UNIX-based. With Windows you use GetTempFileName() and GetTempPath() to generate a path to a temp file. Sample code from MSDN:

http://msdn.microsoft.com/en-us/library/aa363875%28VS.85%29.aspx

Comments

3

I wonder why most of you guys showed him the C way of doing it instead of the C++ way.
Here's fstream.
Try that, deleting a file is OS depended but you can use boost.filesystem to make things easy for you.

1 Comment

That's probably because the OP asked for a temporary file, and there are no standard C++ mechanisms for creating a unique filename. There is nothing in libstdc++ or boost that truly replaces mkstemp().
3

A clean, portable and non-deprecated way of creating a temporary file is provided by Boost:

auto temporary_file = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); // ... boost::filesystem::remove(temporary_file); 

Alternatively using std::filesystem:

char temporary_file_path_buffer[L_tmpnam]; if (const errno_t return_value = tmpnam_s(temporary_file_path_buffer, L_tmpnam); return_value != 0) { throw std::runtime_error("Failed to generate temporary file name"); } std::filesystem::path temporary_file_path = temporary_file_path_buffer; // ... std::filesystem::remove(temporary_file_path); 

Note that tmpnam is deprecated and std::filesystem::unique_path was sadly removed.

Comments

2

If you need a named file (for example, so you can pass the name to another process, perhaps a compiler or editor), then register a cleanup function that removes the file with atexit(). You can use either C++ <iostream> or C FILE * (<cstdio>) to create the file. The not completely standard but widely available mkstemp() function creates a file and tells you its name as well as returning a file descriptor (a third I/O mechanism); you could use the fdopen() function to convert the file descriptor into a FILE *.

If you don't need a named file a C-style FILE * is OK, then look at tmpfile() as suggested by @Tom.

Comments

1

If you want to remove the file as soon as your application closes, use std::tmpfile(). It is safe, you can open a few thousand file per process (see TMP_MAX value) and platform independent.

It will create an empty file, and delete it as soon as it is closed.

#include <cstdio> int main() { std::FILE* temp_file = std::tmpfile(); // create file if(temp_file == nullptr) { // error, temp file cannot be created return -1; } std::fprintf(temp_file, "Some temporary text"); // use the file (write and read content) std::fclose(temp_file); // file removed from disk return 0; } 

Note if your program exits abnormally, it is implementation defined whether the file gets deleted or not.
To get the path of the file, we could use the following (linux implementation is from cppreference, for more details on windows implementation see the last paragraph of my other answer):

#ifdef WIN32 #include <windows.h> #include <io.h> std::string get_path_from_FILE(FILE* file) { int fd = _fileno(file); if (fd == -1) return ""; HANDLE h = (HANDLE)_get_osfhandle(fd); if (h == INVALID_HANDLE_VALUE) return ""; char path[MAX_PATH]; DWORD ret = GetFinalPathNameByHandleA(h, path, MAX_PATH, FILE_NAME_NORMALIZED); if (ret == 0 || ret >= MAX_PATH) return ""; return std::string(path+4); // it starts with "\\?\C:\...." this is why we need +4 } #elif defined __unix__ std::string get_path_from_FILE(FILE* file) { // Linux-specific method to display the tmpfile name char fname[FILENAME_MAX], link[FILENAME_MAX] = {0}; sprintf(fname, "/proc/self/fd/%d", fileno(tmpf)); if (readlink(fname, link, sizeof link - 1) > 0) { return fname; } return ""; } #endif 

If you stick with linux and C style creation, use open() with O_TMPFILE flag. In this case, the file won't be written to disk, unless a name is given to it.

#include <fcntl.h> #include <unistd.h> int main() { int temp_file = open("/tmp/", O_TMPFILE|O_RDWR, 0); if(temp_file == -1) { return -1; // error, temp file cannot be created } const char* my_temporary_content = "It is temporary"; write(temp_file, my_temporary_content, 15); // 15 is length of the const char above close(temp_file); return 0; } 

Here, the open's first parameter is a directory. Since c++17, we can use temp_directory_path() to determine the temporary directory path.


What is the danger of tmpnam()?
It gives a name that was unique in the time of calling the function, not when creating the file. Therefore, someone (e.g. an attacker, or another process) can create the file after the tmpnam() call, but before the open() call.
This is why one should use the O_EXCL flag to make sure the file is created by us (and handle error properly).

In this case, the file won't be removed after the process finished

#include <stdio.h> #include <fcntl.h> #include <unistd.h> int main() { int temp_file = -1; while(temp_file == -1){ const char* temp_name = tmpnam(nullptr); // this is the dangerous part temp_file = open(temp_name, O_CREAT|O_EXCL|O_RDWR, S_IRUSR | S_IWUSR); // it is left to the reader to prevent infinite loop } const char* my_temporary_content = "It is temporary"; write(temp_file, my_temporary_content, 15); // 15 is length of the const char above close(temp_file); return 0; } 

Comments

0

Well, assuming you have been successful in creating the temporary file, you can use the remove function to delete it.

The function is declared in stdio.h -

#include <stdio.h> int remove(const char *pathname); 

For example, if you want to delete a file named myfile.txt the code will be

#include<stdio.h> int main() { if(remove("myfile.txt") == -1) { fprintf(stderr,"Remove failed"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } 

I hope by now, you already know how to create the temp file, so this should resolve your query. Hope it helps.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.