0

Is there a portable way of creating temporary files with C++ that get automatically deleted when the program terminates (regardless of whether it crashes, gets killed, or just reaches return 0; in main().).

On Unix systems, I can open a file, delete it and then keep the still existing handle. This works with FILE *, std::fstream etc.

On Windows, this appears not to work. The only way I found is using CreateFile with the FILE_FLAG_DELETE_ON_CLOSE flag.

Is there something smarter that (1) works both on Linux and Windows, (2) has the "the file is removed on when the program terminates" behaviour as on Linux. I would be fine with #ifdef code as long as the file type that I work with is the same on both systems (e.g. std::fstream or FILE *).

I know about this solution, but this appears only to work on graceful exits and would require me to either set up central handlers and manage all temporarily opened files.

Edit: Rephrased the question to "how can I get files on Windows that are automatically removed as removed-but-still-open files in Linux.

Community
  • 1
  • 1
Manuel
  • 6,461
  • 7
  • 40
  • 54
  • 1
    `regardless of how "bad" the crash/exit is` So if I pull the plug out the wall, how is your program going to clean up the files? What most programs do is that on restart of the app, any temp files that were left over are either automatically cleaned up, or friendly programs will ask the user what to do with the files. Of course, you have to name the temp files in a way that your app recognizes that the files were previously created by your program. – PaulMcKenzie May 09 '14 at 14:28
  • @PaulMcKenzie: That's a good question, I should rephrase this to "how can I make Windows behave like Linux with deleted files." – Manuel May 09 '14 at 14:30
  • If auto cleanup of temp files were possible with Windows, I would think that the various Microsoft apps that create temp files would take advantage of this. However, you see that none of them (Word, Excel, Visual Studio, etc.) can do this. Instead, they do what I suggested in the previous comment. – PaulMcKenzie May 09 '14 at 14:32
  • @PaulMcKenzie: It is possible to use CreateFile with the FILE_FLAG_DELETE_ON_CLOSE attribute on Windows. Something like this for `FILE *` or `std::fstream` would be great. – Manuel May 09 '14 at 14:35
  • If that's the case, then maybe open the file with CreateFile and then "convert" the handle to stdio. Try this: http://stackoverflow.com/questions/7369445/is-there-a-windows-equivalent-to-fdopen-for-handles – PaulMcKenzie May 09 '14 at 14:46

2 Answers2

1

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

Creates a temporary binary file, open for update ("wb+" mode, see fopen for details) with a filename 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. If the program terminates abnormally, whether the file is deleted depends on the specific system and library implementation.

For abnormal termination, handle std::terminate by using: http://en.cppreference.com/w/cpp/error/set_terminate

Clean up the file with std::remove and then re-throw. I haven't tested this abornmal termination stuff yet but it should work. The temporary file creation works for sure. I've used it before.

It can be wrapped in a streambuf for usage with streams.

Brandon
  • 22,723
  • 11
  • 93
  • 186
0

Also as a partial solution you can write a class, that deletes the file on destruction. On windows you can use MoveFileExW(filepathFull, NULL, MOVEFILE_DELAY_UNTIL_REBOOT) if that fails to have the file deleted on reboot. All of this can be hidden in the class. See for example: tmpfile.h tmpFile.cpp

Alternatively you can use something like:

struct TmpFile{
    FILE* file;
    TmpFile(std::string path){
#ifdef _WIN32
        HANDLE handle = CreateFile(path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0,
           OPEN_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 0);
        if(handle == INVALID_HANDLE_VALUE) throw "Error";
        int fd = _open_osfhandle((intptr_t)h, _O_APPEND | _O_RDONLY);
        if(fd == -1){ CloseHandle(handle); throw "Error"; }
        file = _fdopen(fd, "a+");
        if(f == NULL){ _close(fd); throw "Error"; }
#else
        file = fopen(path.c_str(), "w+");
        unlink(path.c_str());
#endif
    }
    ~TmpFile(){
        fclose(file);
    }
};

Check the access modifiers and adjust to your needs (especially the error handling) This has the nice properties of RAII and will delete the file even in exception cases. However some failures where the dtor is not called will leak the handle in which case the file might not be deleted on windows.

The Win32 handling is taken from here: https://stackoverflow.com/a/7369662/1930508 Check the explanations there.

Flamefire
  • 5,313
  • 3
  • 35
  • 70