* Add support for cached reads

This commit is contained in:
Phillip Stephens 2015-07-09 20:05:55 -07:00
parent a19dcad876
commit a7c180db00
2 changed files with 86 additions and 7 deletions
include/Athena
src/Athena

View File

@ -12,7 +12,7 @@ namespace io
class FileReader : public IStreamReader
{
public:
FileReader(const std::string& filename);
FileReader(const std::string& filename, atUint32 cacheSize = (32 * 1024));
virtual ~FileReader();
inline const std::string& filename() const
{return m_filename;}
@ -27,10 +27,14 @@ public:
atUint64 length() const;
atUint64 readUBytesToBuf(void* buf, atUint64 len);
void setCacheSize(const atUint32 blockSize);
protected:
std::string m_filename;
FILE* m_fileHandle;
atUint8 m_currentByte;
std::unique_ptr<atUint8[]> m_cacheData;
atUint32 m_blockSize;
atInt32 m_curBlock;
atUint64 m_offset;
};
} // io
} // Athena

View File

@ -14,10 +14,13 @@ namespace Athena
{
namespace io
{
FileReader::FileReader(const std::string& filename)
FileReader::FileReader(const std::string& filename, atUint32 cacheSize)
: m_filename(filename),
m_fileHandle(NULL)
m_fileHandle(nullptr),
m_cacheData(nullptr),
m_offset(0)
{
setCacheSize(cacheSize);
open();
}
@ -50,7 +53,37 @@ void FileReader::close()
void FileReader::seek(atInt64 pos, SeekOrigin origin)
{
if (fseeko64(m_fileHandle, pos, (int)origin) != 0)
// check block position
if (m_blockSize > 0)
{
atUint64 oldOff = m_offset;
switch(origin)
{
case SeekOrigin::Begin:
m_offset = pos;
break;
case SeekOrigin::Current:
m_offset += pos;
break;
case SeekOrigin::End:
m_offset = length() - pos;
break;
}
if (m_offset > length())
{
oldOff = m_offset;
THROW_INVALID_OPERATION_EXCEPTION("Unable to seek in file");
}
size_t block = m_offset / m_blockSize;
if (block != m_curBlock)
{
fseeko64(m_fileHandle, block * m_blockSize, SEEK_SET);
fread(m_cacheData.get(), 1, m_blockSize, m_fileHandle);
m_curBlock = block;
}
}
else if (fseeko64(m_fileHandle, pos, (int)origin) != 0)
THROW_INVALID_OPERATION_EXCEPTION("Unable to seek in file");
}
@ -59,7 +92,10 @@ atUint64 FileReader::position() const
if (!isOpen())
THROW_INVALID_OPERATION_EXCEPTION_RETURN(0, "File not open");
return ftello64(m_fileHandle);
if (m_blockSize > 0)
return m_offset;
else
return ftello64(m_fileHandle);
}
atUint64 FileReader::length() const
@ -75,7 +111,46 @@ atUint64 FileReader::readUBytesToBuf(void* buf, atUint64 len)
if (!isOpen())
THROW_INVALID_OPERATION_EXCEPTION_RETURN(0, "File not open for reading");
return fread(buf, 1, len, m_fileHandle);
if (m_blockSize <= 0)
return fread(buf, 1, len, m_fileHandle);
else
{
size_t block = m_offset / m_blockSize;
atUint64 cacheOffset = m_offset % m_blockSize;
atUint64 cacheSize;
atUint64 rem = len;
atUint8* dst = (atUint8*)buf;
while (rem)
{
if (block != m_curBlock)
{
fseeko64(m_fileHandle, block * m_blockSize, SEEK_SET);
fread(m_cacheData.get(), 1, m_blockSize, m_fileHandle);
m_curBlock = block;
}
cacheSize = rem;
if (cacheSize + cacheOffset > m_blockSize)
cacheSize = m_blockSize - cacheOffset;
memcpy(dst, m_cacheData.get() + cacheOffset, cacheSize);
dst += cacheSize;
rem -= cacheSize;
cacheOffset = 0;
++block;
}
m_offset += len;
return dst - (atUint8*)buf;
}
}
void FileReader::setCacheSize(const atUint32 blockSize)
{
m_blockSize = blockSize;
m_curBlock = -1;
if (m_blockSize > 0)
m_cacheData.reset(new atUint8[m_blockSize]);
}
} // io