#include <iostream>
#include <fstream>
#include <stdio.h>
namespace fs
{
class tempfile
{
public:
// tempfile constructor.
explicit tempfile(char const * const _file_name, std::ios_base::openmode _mode = std::ios_base::binary, char const * const _temp_dir = 0 , char const * const _prefix = "tfx") :
m_file_name( _file_name ),
m_temp_name( tempnam(_temp_dir, _prefix) ),
m_temp_file( m_temp_name.c_str(), std::ios_base::out | _mode )
{
}
// check to see if the temp file is open and ready for writing.
bool is_open() const
{
return m_temp_file.is_open();
}
// boolean operator returns true if the temporary file is ready for writing.
operator bool() const
{
return is_open();
}
// get the temporary file stream.
std::ofstream & temp()
{
return m_temp_file;
}
// closes the temp file but doesn't commit the changes.
void close( bool erase_temp = false )
{
// close the temp file.
if ( m_temp_file )
m_temp_file.close();
// kill the temp file.
if ( erase_temp )
cleanup();
}
// erase the temporary file.
void cleanup()
{
remove( m_temp_name.c_str() );
}
// replaces the final file with the temporary. note: every
// attempt is made to preserve the original file.
bool commit( bool keep_backup = true )
{
if ( is_open() ) {
// close the temp file to move the contents.
close( false );
// add backup strategies to handle backup. three strategy ideas:
// 1. delete - delete the original file.
// 2. rename - rename the original file (ie, keep backup).
// 3. archive - store the file in source control or database or offsite.
// for now, rename the old file.
std::string oldfilename = m_file_name;
oldfilename += std::string(".bck");
remove( oldfilename.c_str() );
rename( m_file_name.c_str(), oldfilename.c_str() );
// rename it to the new file.
if ( rename(m_temp_name.c_str(), m_file_name.c_str()) == 0 )
{
if (!keep_backup)
remove( oldfilename.c_str() );
return true;
}
// if temp rename fails, restore the original file.
remove( m_file_name.c_str() );
rename( oldfilename.c_str(), m_file_name.c_str() );
}
// if you get here, attempt to close & remove the temporary file.
close( true );
return false;
}
// close the file assuming we will explicitly commit the results.
~tempfile()
{
close( true );
}
private:
std::string m_file_name;
std::string m_temp_name;
std::ofstream m_temp_file;
private:
tempfile(); // disabled
};
}
int main()
{
fs::tempfile test("test.txt");
if ( test ) {
test.temp() << "nothing to see here...\n";
if ( test.commit() )
std::cout << "Success!" << std::endl;
else
std::cout << "Failure :( " << std::endl;
}
return 0;
}