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
//! 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
{
@ -49,24 +103,16 @@ void readFile( const std::string& path, std::string& content )
}
if ( successful ) {
#ifdef _MSC_VER
FILE* file;
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
FileHandler file{ path.c_str(), "rb" };
if ( ! file.valid() ) {
// unable to open the file
//throw("cannot read");
return;
}
/*FILE *dest = fopen( out_path.c_str(), "wb" );*/
// decompress until deflate stream ends or end of file is reached
do {
strm.avail_in = static_cast<unsigned>(fread( in, 1, CHUNK, file ));
if ( ferror( file ) ) {
if ( file.error() ) {
// error reading
(void)inflateEnd( &strm );
/*successful = false;*/
@ -111,11 +157,7 @@ void readFile( const std::string& path, std::string& content )
// clean up and return
(void)inflateEnd( &strm );
successful = (ret == Z_STREAM_END) ? true : false;
if ( fclose( file ) ) {
// error while trying to close file pointer
throw GenericException( "Failed to close file pointer" );
}
//delete file;
file.close(); // throws GenericException on failure
}
if ( content.empty() ) {
// probably not a gzip compressed file

View File

@ -10,6 +10,49 @@
#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
{
@ -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 )
{
// read the whole file
std::ifstream file;
try {
/*constexpr std::size_t read_size = std::size_t(4096);*/
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" );
}
FileHandler<std::ifstream> file{ path }; // throws std::ios_base::failure on failure
// add bit exceptions
file.exceptions( std::ifstream::failbit );
file.exceptions( std::ios_base::badbit );
file.setException( std::ifstream::failbit );
file.setException( std::ios_base::badbit );
// read the whole file
content = std::string(
std::istreambuf_iterator<char>( file ),
std::istreambuf_iterator<char>( *file ),
std::istreambuf_iterator<char>() );
} catch ( const std::ios_base::failure& ) {
// failed reading
if ( file.is_open() ) {
file.close();
}
throw;
} catch (...) {
if ( file.is_open() ) {
file.close();
}
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 )
{
std::ofstream file;
try {
file.open( 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" );
}
FileHandler<std::ofstream> file{ path }; // throws std::ios_base::failure on failure
// add bit exceptions
file.exceptions( std::ifstream::failbit );
file.exceptions( std::ios_base::badbit );
file.setException( std::ios_base::failbit );
file.setException( std::ios_base::badbit );
// write the content
file << content << std::endl;
*file << content << std::endl;
} catch ( const std::ios_base::failure& ) {
// failed writing
if ( file.is_open() ) {
file.close();
}
throw;
} catch (...) {
if ( file.is_open() ) {
file.close();
}
throw std::exception(); // already catched
}
if ( file.is_open() ) {
file.close();
}
}
} // namespace IOUtils