fork(1) download
  1. #include <iostream>
  2. #include <fstream>
  3. #include <stdio.h>
  4.  
  5. namespace fs
  6. {
  7. class tempfile
  8. {
  9. public:
  10. // tempfile constructor.
  11. 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") :
  12. m_file_name( _file_name ),
  13. m_temp_name( tempnam(_temp_dir, _prefix) ),
  14. m_temp_file( m_temp_name.c_str(), std::ios_base::out | _mode )
  15. {
  16. }
  17.  
  18. // check to see if the temp file is open and ready for writing.
  19. bool is_open() const
  20. {
  21. return m_temp_file.is_open();
  22. }
  23.  
  24. // boolean operator returns true if the temporary file is ready for writing.
  25. operator bool() const
  26. {
  27. return is_open();
  28. }
  29.  
  30. // get the temporary file stream.
  31. std::ofstream & temp()
  32. {
  33. return m_temp_file;
  34. }
  35.  
  36. // closes the temp file but doesn't commit the changes.
  37. void close( bool erase_temp = false )
  38. {
  39. // close the temp file.
  40. if ( m_temp_file )
  41. m_temp_file.close();
  42.  
  43. // kill the temp file.
  44. if ( erase_temp )
  45. cleanup();
  46. }
  47.  
  48. // erase the temporary file.
  49. void cleanup()
  50. {
  51. remove( m_temp_name.c_str() );
  52. }
  53.  
  54. // replaces the final file with the temporary. note: every
  55. // attempt is made to preserve the original file.
  56. bool commit( bool keep_backup = true )
  57. {
  58. if ( is_open() ) {
  59. // close the temp file to move the contents.
  60. close( false );
  61.  
  62. // add backup strategies to handle backup. three strategy ideas:
  63. // 1. delete - delete the original file.
  64. // 2. rename - rename the original file (ie, keep backup).
  65. // 3. archive - store the file in source control or database or offsite.
  66. // for now, rename the old file.
  67. std::string oldfilename = m_file_name;
  68. oldfilename += std::string(".bck");
  69. remove( oldfilename.c_str() );
  70. rename( m_file_name.c_str(), oldfilename.c_str() );
  71.  
  72. // rename it to the new file.
  73. if ( rename(m_temp_name.c_str(), m_file_name.c_str()) == 0 )
  74. {
  75. if (!keep_backup)
  76. remove( oldfilename.c_str() );
  77.  
  78. return true;
  79. }
  80.  
  81. // if temp rename fails, restore the original file.
  82. remove( m_file_name.c_str() );
  83. rename( oldfilename.c_str(), m_file_name.c_str() );
  84. }
  85.  
  86. // if you get here, attempt to close & remove the temporary file.
  87. close( true );
  88.  
  89. return false;
  90. }
  91.  
  92. // close the file assuming we will explicitly commit the results.
  93. ~tempfile()
  94. {
  95. close( true );
  96. }
  97.  
  98. private:
  99. std::string m_file_name;
  100. std::string m_temp_name;
  101. std::ofstream m_temp_file;
  102.  
  103. private:
  104. tempfile(); // disabled
  105. };
  106. }
  107.  
  108. int main()
  109. {
  110. fs::tempfile test("test.txt");
  111.  
  112. if ( test ) {
  113. test.temp() << "nothing to see here...\n";
  114.  
  115. if ( test.commit() )
  116. std::cout << "Success!" << std::endl;
  117. else
  118. std::cout << "Failure :( " << std::endl;
  119. }
  120.  
  121. return 0;
  122. }
  123.  
  124.  
  125.  
Success #stdin #stdout 0.02s 2816KB
stdin
Standard input is empty
stdout
Failure :(