Monday, 2 December 2013

Data Access Layer for reading and writing files in C++

Data Access Layer :

Data access layer (DAL) Provides simplified access to data stored in persisted storage of some kind. DAL may provide a reference to an object in terms of oops.This allows the client (or user) modules to be created with a higher level of abstraction. Achieving data abstraction for writing data to files and reading data from files is a big challenge ahead of us.

Let us see how we can provide abstraction for reading and writing files in c++. Best way of encapsulation of data is done through classes. 

DataWriter class: 

DataWriter class provides a way to write any type of data into a file.

1. Create DataWriter object.
2. Call WriteData method.
3. Close the writer.

source code :
class DataWriter
{
public:
DataWriter()
{
m_in = nullptr;
m_error = 0;
}

DataWriter(const wchar_t* fileName, const wchar_t* fileMode)
{
OpenWriter(fileName, fileMode);
}

~DataWriter()
{
CloseWriter();
}

inline void OpenWriter(const wchar_t* fileName, const wchar_t* fileMode)
{
if(!fileName)
throw std::exception("file name cant be empty");
if(!fileMode)
throw std::exception("file mode cant be empty");

m_error =  _wfopen_s(&m_in, fileName, fileMode);

if(m_error == EINVAL)
{
CloseWriter();
throw std::exception("error opening file");
}
}

inline void CloseWriter()
{
if(m_in)
{
m_error = _fclose_nolock(m_in);
m_in = nullptr;
}
}

template <typename T> inline void WriteData(T* ptr, long long lengthInBytes)
{
m_error =  _fwrite_nolock(ptr, lengthInBytes, 1, in);
if(m_error != lengthInBytes)
{
CloseWriter();
throw std::exception("error writing to file");
}
}

private:
FILE*  m_in;
errno_t m_error;

};

DataReader class: 

DataReader class provides a way to read any type of data from a file.

1. Create DataReader object.
2. Call ReadData method.
3. Close the reader.

source code :
class DataReader
{
public:
DataReader()
{
m_in = nullptr;
m_error = 0;
}

DataReader(const wchar_t* fileName, const wchar_t* fileMode)
{
OpenReader(fileName, fileMode);
}

~DataReader()
{
CloseReader();
}

inline void OpenReader(const wchar_t* fileName, const wchar_t* fileMode)
{
if(!fileName)
throw std::exception("file name cant be empty");
if(!fileMode)
throw std::exception("file mode cant be empty");

m_error =  _wfopen_s(&m_in, fileName, fileMode);

if(m_error == EINVAL)
{
CloseReader();
throw std::exception("error opening file");
}
}

inline void CloseReader()
{
if(m_in)
{
m_error = _fclose_nolock(m_in);
m_in = nullptr;
}
}

template <typename T> inline void ReadData(T* ptr, long long lengthInBytes)
{
m_error =  _fread_nolock(ptr, lengthInBytes, 1, in);
if(m_error != lengthInBytes)
{
CloseReader();
throw std::exception("error writing to file");
}
}

private:
FILE*  m_in;
errno_t m_error;

};