Introduced FileHandler classes

Wrapper classes to handle resources following the RAII principle
This commit is contained in:
Valentino Orlandi 2024-01-07 19:14:56 +01:00
parent 2f8ec16043
commit 909ce98c5b
Signed by: elB4RTO
GPG key ID: 1719E976DB2D4E71
2 changed files with 110 additions and 59 deletions

View file

@ -24,6 +24,60 @@
#define CHUNK 16384 #define CHUNK 16384
//! RAII class to handle s file resource
class FileHandler
{
FILE* file;
public:
explicit FileHandler( const char* path, const char* mode )
: file{ nullptr }
{
#ifdef _MSC_VER
fopen_s( &this->file, path, mode );
#else
this->file = fopen( path, mode );
#endif
}
~FileHandler()
{
if ( this->valid() ) {
fclose( this->file );
}
}
FileHandler(const FileHandler&) = delete;
FileHandler(FileHandler&&) = delete;
FileHandler& operator=(const FileHandler&) = delete;
FileHandler& operator=(FileHandler&&) = delete;
inline operator FILE*()
{
return this->file;
}
inline bool valid() const noexcept
{
return this->file != NULL;
}
inline bool error() const noexcept
{
return ferror( this->file );
}
inline void close()
{
if ( fclose( this->file ) ) {
throw GenericException( "Failed to close file pointer" );
}
this->file = nullptr;
}
};
namespace GZutils namespace GZutils
{ {
@ -49,24 +103,16 @@ void readFile( const std::string& path, std::string& content )
} }
if ( successful ) { if ( successful ) {
#ifdef _MSC_VER FileHandler file{ path.c_str(), "rb" };
FILE* file; if ( ! file.valid() ) {
const int err{ fopen_s( &file, path.c_str(), "rb" ) };
/*FILE *dest = fopen ( out_path.c_str(), "wb" );*/
if ( file == NULL || err != 0 ) {
#else
FILE* file = fopen( path.c_str(), "rb" );
/*FILE *dest = fopen( out_path.c_str(), "wb" );*/
if ( file == NULL ) {
#endif
// unable to open the file // unable to open the file
//throw("cannot read");
return; return;
} }
/*FILE *dest = fopen( out_path.c_str(), "wb" );*/
// decompress until deflate stream ends or end of file is reached // decompress until deflate stream ends or end of file is reached
do { do {
strm.avail_in = static_cast<unsigned>(fread( in, 1, CHUNK, file )); strm.avail_in = static_cast<unsigned>(fread( in, 1, CHUNK, file ));
if ( ferror( file ) ) { if ( file.error() ) {
// error reading // error reading
(void)inflateEnd( &strm ); (void)inflateEnd( &strm );
/*successful = false;*/ /*successful = false;*/
@ -111,11 +157,7 @@ void readFile( const std::string& path, std::string& content )
// clean up and return // clean up and return
(void)inflateEnd( &strm ); (void)inflateEnd( &strm );
successful = (ret == Z_STREAM_END) ? true : false; successful = (ret == Z_STREAM_END) ? true : false;
if ( fclose( file ) ) { file.close(); // throws GenericException on failure
// error while trying to close file pointer
throw GenericException( "Failed to close file pointer" );
}
//delete file;
} }
if ( content.empty() ) { if ( content.empty() ) {
// probably not a gzip compressed file // probably not a gzip compressed file

View file

@ -10,6 +10,49 @@
#include <fstream> #include <fstream>
//! RAII class to handle a file stream resource
template<typename Stream>
class FileHandler
{
Stream file;
public:
explicit FileHandler( const std::string& path )
: file{ path }
{
if ( ! this->file.is_open() ) {
throw std::ios_base::failure( "file is not open" );
}
if ( ! this->file.good() ) {
throw std::ios_base::failure( "file is not good" );
}
}
~FileHandler()
{
if ( this->file.is_open() ) {
this->file.close();
}
}
FileHandler(const FileHandler&) = delete;
FileHandler(FileHandler&&) = delete;
FileHandler& operator=(const FileHandler&) = delete;
FileHandler& operator=(FileHandler&&) = delete;
inline Stream& operator*()
{
return this->file;
}
inline void setException( const std::ios_base::iostate e )
{
this->file.exceptions( e );
}
};
namespace IOutils namespace IOutils
{ {
@ -96,39 +139,22 @@ bool renameAsCopy( std::string_view path, std::error_code& err ) noexcept(true)
void readFile( const std::string& path, std::string& content ) void readFile( const std::string& path, std::string& content )
{ {
// read the whole file // read the whole file
std::ifstream file;
try { try {
/*constexpr std::size_t read_size = std::size_t(4096);*/ FileHandler<std::ifstream> file{ path }; // throws std::ios_base::failure on failure
file = std::ifstream(path);
if ( ! file.is_open() ) {
throw std::ios_base::failure( "file is not open" );
}
if ( ! file.good() ) {
throw std::ios_base::failure( "file is not good" );
}
// add bit exceptions // add bit exceptions
file.exceptions( std::ifstream::failbit ); file.setException( std::ifstream::failbit );
file.exceptions( std::ios_base::badbit ); file.setException( std::ios_base::badbit );
// read the whole file // read the whole file
content = std::string( content = std::string(
std::istreambuf_iterator<char>( file ), std::istreambuf_iterator<char>( *file ),
std::istreambuf_iterator<char>() ); std::istreambuf_iterator<char>() );
} catch ( const std::ios_base::failure& ) { } catch ( const std::ios_base::failure& ) {
// failed reading // failed reading
if ( file.is_open() ) {
file.close();
}
throw; throw;
} catch (...) { } catch (...) {
if ( file.is_open() ) {
file.close();
}
throw std::exception(); // already catched throw std::exception(); // already catched
} }
if ( file.is_open() ) {
file.close();
}
} }
@ -218,37 +244,20 @@ void randomLines( const std::string& path, std::vector<std::string>& lines, cons
void writeOnFile( const std::string& path, std::string_view content ) void writeOnFile( const std::string& path, std::string_view content )
{ {
std::ofstream file;
try { try {
file.open( path ); FileHandler<std::ofstream> file{ path }; // throws std::ios_base::failure on failure
if ( ! file.is_open() ) {
throw std::ios_base::failure( "file is not open" );
}
if ( ! file.good() ) {
throw std::ios_base::failure( "file is not good" );
}
// add bit exceptions // add bit exceptions
file.exceptions( std::ifstream::failbit ); file.setException( std::ios_base::failbit );
file.exceptions( std::ios_base::badbit ); file.setException( std::ios_base::badbit );
// write the content // write the content
file << content << std::endl; *file << content << std::endl;
} catch ( const std::ios_base::failure& ) { } catch ( const std::ios_base::failure& ) {
// failed writing // failed writing
if ( file.is_open() ) {
file.close();
}
throw; throw;
} catch (...) { } catch (...) {
if ( file.is_open() ) {
file.close();
}
throw std::exception(); // already catched throw std::exception(); // already catched
} }
if ( file.is_open() ) {
file.close();
}
} }
} // namespace IOUtils } // namespace IOUtils