📄 tddatabase.cpp
字号:
#include "tddatabase.h"
const char* TDDB_ErrorCodeToString( int iErrorCode )
{
switch( iErrorCode ){
case TDDB_OK:
return "TDDB_OK";
case TDDBERR_READ_ERROR:
return "TDDBERR_READ_ERROR";
case TDDBERR_COULD_NOT_OPEN:
return "TDDBERR_COULD_NOT_OPEN";
case TDDBERR_NO_COLUMNS :
return "TDDBERR_NO_COLUMNS";
case TDDBERR_FILE_NOT_FOUND:
return "TDDBERR_FILE_NOT_FOUND";
case TDDBERR_WRITE_ERROR :
return "TDDBERR_WRITE_ERROR";
case TDDBERR_PREPARE_ERROR:
return "TDDBERR_PREPARE_ERROR";
case TDDBERR_SEEK_ERROR:
return "TDDBERR_SEEK_ERROR";
case TDDBERR_DATABASE_NOT_OPEN:
return "TDDBERR_DATABASE_NOT_OPEN";
case TDDBERR_INVALID_RECORD:
return "TDDBERR_INVALID_RECORD";
default:
return "Unrecognised error code";
}
}
CTDDatabase::CTDDatabase(void)
: _lpFile(0)
, _lFirstRecord(-1)
{
_tableDef.Columns = 0;
_tableDef.iColumnCount = 0;
}
CTDDatabase::~CTDDatabase(void)
{
ResetEverything();
}
int CTDDatabase::Open( const char* szFileName )
{
ResetEverything();
//check if file exists
_lpFile = fopen( szFileName, "r");
if( _lpFile == 0 ){
return TDDBERR_FILE_NOT_FOUND;
}
//attemp to open the file
_lpFile = fopen( szFileName, "r+" );
if( _lpFile == 0 )
return TDDBERR_COULD_NOT_OPEN;
//read in the table definition
//read in the number of columns
if( fread( &(_tableDef.iColumnCount) , sizeof(_tableDef.iColumnCount), 1, _lpFile) != 1){
ResetEverything();
return TDDBERR_READ_ERROR;
}
//allocate enough space for columns
_tableDef.Columns = new TDDBColumn[_tableDef.iColumnCount];
//read in all the columns
for( unsigned int i = 0; i < _tableDef.iColumnCount; i++ ){
//read in the column name
if( fread(&(_tableDef.Columns[i].szName), TDDB_MAX_COLUMN_NAME, 1, _lpFile) != 1 ){
ResetEverything();
return TDDBERR_READ_ERROR;
}
//read in the column size in bytes
if( fread(&(_tableDef.Columns[i].iBytes), sizeof( _tableDef.Columns[i].iBytes ), 1, _lpFile) != 1){
ResetEverything();
return TDDBERR_READ_ERROR;
}
}
//save where the first record is
_lFirstRecord = ftell( _lpFile );
return TDDB_OK;
}
int CTDDatabase::Close( void )
{
ResetEverything();
return TDDB_OK;
}
int CTDDatabase::CreateNew( const char* szFileName, TDDBTable* tableDef )
{
//attempt to open new file
FILE* lpNewDBFile = fopen( szFileName, "w" );
if( lpNewDBFile == 0 )
return TDDBERR_COULD_NOT_OPEN;
//write the table def header
if( fwrite( &(tableDef->iColumnCount), sizeof(tableDef->iColumnCount), 1, lpNewDBFile ) != 1)
return TDDBERR_WRITE_ERROR;
for( unsigned int i = 0; i < tableDef->iColumnCount; i++ ){
//write column name
if( fwrite(&(tableDef->Columns[i].szName), TDDB_MAX_COLUMN_NAME, 1, lpNewDBFile) != 1 )
return TDDBERR_WRITE_ERROR;
//write column size
if( fwrite(&(tableDef->Columns[i].iBytes), sizeof(tableDef->Columns[i].iBytes), 1, lpNewDBFile) != 1 )
return TDDBERR_WRITE_ERROR;
}
fclose( lpNewDBFile );
return TDDB_OK;
}
unsigned int CTDDatabase::GetRecordSizeInBytes()
{
if( !IsOpen() )
return 0;
if (!(_tableDef.iColumnCount > 0))
return 0;
unsigned int iByteCount = sizeof(TDR_RECORD_HEADER);
for( unsigned int i = 0; i < _tableDef.iColumnCount; i++ ){
iByteCount += _tableDef.Columns[i].iBytes;
}
return iByteCount;
}
int CTDDatabase::ResetEverything( void )
{
//if anything needs to be cleaned up
int iRet = (( _lpFile != 0 ) || ( _tableDef.Columns != 0))? 1 : 0 ;
if( _lpFile != 0 ){
fclose( _lpFile );
_lpFile = 0;
}
_lFirstRecord = -1;
if( _tableDef.Columns != 0 ){
delete[] _tableDef.Columns;
_tableDef.Columns = 0;
}
_tableDef.iColumnCount = 0;
return iRet;
}
CTDRecord CTDDatabase::CreateRecord( void )
{
if( !IsOpen() )
return CTDRecord ( 0, 0 );
return CTDRecord( &_tableDef, GetRecordSizeInBytes() );
}
int CTDDatabase::GetRecord( CTDRecord* recordOut, unsigned int iIndex )
{
if( !IsOpen() )
return TDDBERR_DATABASE_NOT_OPEN;
if( !recordOut->IsValid() )
return TDDBERR_INVALID_RECORD;
//find the record's byte offset in the database file
long lOffset = GetRecordOffset( iIndex );
//read up to the offset
if( fseek( _lpFile, lOffset, SEEK_SET ) != 0 )
return TDDBERR_SEEK_ERROR;
//read the record from the file into the record object
if( fread( (void*)recordOut->_lpBuffer, recordOut->_iBytes, 1, _lpFile ) != 1 )
return TDDBERR_READ_ERROR;
return TDDB_OK;
}
int CTDDatabase::SetRecord( CTDRecord* recordIn, unsigned int iIndex )
{
if( !IsOpen() )
return TDDBERR_DATABASE_NOT_OPEN;
if( !recordIn->IsValid() )
return TDDBERR_INVALID_RECORD;
//find the record's byte offset in the database file
long lOffset = GetRecordOffset( iIndex );
//read up to the offset
if( fseek( _lpFile, lOffset, SEEK_SET ) != 0 )
return TDDBERR_SEEK_ERROR;
//overwrite the previous record
if( fwrite( (const void*)recordIn->_lpBuffer, recordIn->_iBytes, 1, _lpFile ) != 1 )
return TDDBERR_WRITE_ERROR;
return TDDB_OK;
}
int CTDDatabase::AddRecord( CTDRecord* recordIn )
{
if( !IsOpen() )
return TDDBERR_DATABASE_NOT_OPEN;
if( !recordIn->IsValid() )
return TDDBERR_INVALID_RECORD;
//find the first deleted record
unsigned int iRecordCount;
unsigned int iRet = GetRecordCount( &iRecordCount );
if( iRet != TDDB_OK )
return iRet;
unsigned int iRecordSize = GetRecordSizeInBytes();
void* vpRecordBuffer = (void*) new char[iRecordSize];
//cycle through all the records
if( fseek( _lpFile, _lFirstRecord, SEEK_SET ) != 0 ){
delete vpRecordBuffer;
return TDDBERR_SEEK_ERROR;
}
for( unsigned int i = 0; i < iRecordCount; i++ ){
long lRecordPosition = ftell( _lpFile );
//read in the record
if( fread( vpRecordBuffer, iRecordSize, 1, _lpFile ) != 1 ){
delete[] vpRecordBuffer;
return TDDBERR_READ_ERROR;
}
//if the record just read is marked as deleted
if( *((TDR_RECORD_HEADER*)vpRecordBuffer) & TDRH_MASK_DELETED ){
//rewind and overwrite it
fseek( _lpFile, lRecordPosition, SEEK_SET );
if( fwrite( recordIn->_lpBuffer, recordIn->_iBytes, 1, _lpFile ) != 1 ){
delete[] vpRecordBuffer;
return TDDBERR_WRITE_ERROR;
} else {
return TDDB_OK;
}
}
}
//if we reached EOF and didn't find a deleted record, write the record at the end
if( fseek( _lpFile, 0, SEEK_CUR ) != 0 ){
delete[] vpRecordBuffer;
return TDDBERR_WRITE_ERROR;
}
if( fwrite( recordIn->_lpBuffer, recordIn->_iBytes, 1, _lpFile ) != 1 ){
delete[] vpRecordBuffer;
return TDDBERR_WRITE_ERROR;
}
delete[] vpRecordBuffer;
return TDDB_OK;
}
int CTDDatabase::DeleteRecord( unsigned int iIndex )
{
long lOffset = GetRecordOffset( iIndex );
TDR_RECORD_HEADER rh;
//read in the header
if( fread( (void*) &rh, sizeof(rh), 1, _lpFile ) != 1 )
return TDDBERR_READ_ERROR;
//set the deleted flag
rh |= TDRH_MASK_DELETED;
//put the header back
if( fseek( _lpFile, lOffset, SEEK_SET ) != 0 )
return TDDBERR_SEEK_ERROR;
if( fwrite( (void*) &rh, sizeof(rh), 1, _lpFile ) != 1 )
return TDDBERR_WRITE_ERROR;
return TDDB_OK;
}
int CTDDatabase::GetRecordCount( unsigned int* lpiCount )
{
if( !IsOpen() )
return TDDBERR_DATABASE_NOT_OPEN;
if( fseek( _lpFile, 0, SEEK_END ) != 0 )
return TDDBERR_SEEK_ERROR;
long lBytesInFile = ftell( _lpFile );
unsigned int iRecordSize = GetRecordSizeInBytes();
*lpiCount = (unsigned int)((lBytesInFile - _lFirstRecord) / iRecordSize);
return TDDB_OK;
}
int CTDDatabase::GetValidRecordCount( unsigned int* lpiCount )
{
if( !IsOpen() )
return TDDBERR_DATABASE_NOT_OPEN;
if( fseek( _lpFile, _lFirstRecord, SEEK_SET ) != 0 )
return TDDBERR_SEEK_ERROR;
unsigned int iCount = 0;
unsigned int iRecordSize = GetRecordSizeInBytes();
void* vpRecordBuffer = (void*) new char[iRecordSize];
//cycle through every record
while( fread( vpRecordBuffer, iRecordSize, 1, _lpFile ) == 1 ){
// if the record isn't deleted, increment
if( !(*((TDR_RECORD_HEADER*)vpRecordBuffer) & TDRH_MASK_DELETED) )
iCount++;
}
*lpiCount = iCount;
delete[] vpRecordBuffer;
return TDDB_OK;
}
long CTDDatabase::GetRecordOffset( unsigned int iIndex )
{
return ( _lFirstRecord + ((long)iIndex * (long)GetRecordSizeInBytes()) );
}
int CTDDatabase::IsOpen( void )
{
return ( _lpFile != 0 );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -