How can I delete a file upon its close in C++ on Linux?
I wish for a fi开发者_运维知识库le to be deleted from disk only when it is closed. Up until that point, other processes should be able to see the file on disk and read its contents, but eventually after the close of the file, it should be deleted from disk and no longer visible on disk to other processes.
Open the file, then delete it while it's open. Other processes will be able to use the file, but as soon as all handles to file are closed, it will be deleted.
Edit: based on the comments WilliamKF added later, this won't accomplish what he wants -- it'll keep the file itself around until all handles to it are closed, but the directory entry for the file name will disappear as soon as you call unlink
/remove
.
Open files in Unix are reference-counted. Every open(2)
increments the counter, every close(2)
decrements it. The counter is shared by all processes on the system.
Then there's a link count for a disk file. Brand-new file gets a count of one. The count is incremented by the link(2)
system call. The unlink(2)
decrements it. File is removed from the file system when this count drops to zero.
The only way to accomplish what you ask is to open the file in one process, then unlink(2)
it. Other processes will be able to open(2)
or stat(2)
it between open(2)
and unlink(2)
. Assuming the file had only one link, it'll be removed when all processes that have it open close it.
Use unlink
#include <unistd.h>
int unlink(const char *pathname);
unlink() deletes a name from the filesystem. If that name was the last link to a file and no processes have the file open the file is deleted and the space it was using is made available for reuse.
If the name was the last link to a file but any processes still have the file open the file will remain in existence until the last file descriptor referring to it is closed.
If the name referred to a symbolic link the link is removed.
If the name referred to a socket, fifo or device the name for it is removed but processes which have the object open may continue to use it.
Not sure, but you could try remove, but it looks more like c-style.
Maybe boost::filesystem::remove?
bool remove( const path & ph );
Precondition: !ph.empty()
Returns: The value of exists( ph ) prior to the establishment of the postcondition.
Postcondition: !exists( ph )
Throws: if ph.empty() || (exists(ph) && is_directory(ph) && !is_empty(ph)). See empty path rationale.
Note: Symbolic links are themselves deleted, rather than what they point to being deleted.
Rationale: Does not throw when !exists( ph ) because not throwing:
Works correctly if ph is a dangling symbolic link. Is slightly easier-to-use for many common use cases. Is slightly higher-level because it implies use of postcondition semantics rather than effects semantics, which would be specified in the somewhat lower-level terms of interactions with the operating system. There is, however, a slight decrease in safety because some errors will slip by which otherwise would have been detected. For example, a misspelled path name could go undetected for a long time.
The initial version of the library threw an exception when the path did not exist; it was changed to reflect user complaints.
You could create a wrapper class that counts references, using one of the above methods to delete de file .
class MyFileClass{
static unsigned _count;
public:
MyFileClass(std::string& path){
//open file with path
_count++;
}
//other methods
~MyFileClass(){
if (! (--_count)){
//delete file
}
}
};
unsigned MyFileClass::_count = 0; //elsewhere
I think you need to extend your notion of “closing the file” beyond fclose
or std::fstream::close
to whatever you intend to do. That might be as simple as
class MyFile : public std::fstream {
std::string filename;
public:
MyFile(const std::string &fname) : std::fstream(fname), filename(fname) {}
~MyFile() { unlink(filename); }
}
or it may be something much more elaborate. For all I know, it may even be much simpler – if you close files only at one or two places in your code, the best thing to do may be to simply unlink
the file there (or use boost::filesystem::remove, as Tom suggests).
OTOH, if all you want to achieve is that processes started from your process can use the file, you may not need to keep it lying around on disk at all. fork
ed processes inherit open files. Don't forget to dup
them, lest seeking in the child influences the position in the parent or vice versa.
精彩评论