|
В этом разделе представлены классы, которые предназначены для работы с абстрактными файлами. Методы этих классов аналогичны соответствующим функциям из библиотеки stdio.
class IReadFile
{
public:
virtual nat read ( void * p, const nat size, const nat count ) = 0;
virtual bool getc ( void * p ) = 0;
virtual ~IReadFile() {}
};
Класс IReadFile предназначен для чтения данных. Метод read считывает информацию блоками размером size и количеством count в память с адресом p. Возращаемое значение - это реальное количество прочитанных блоков. Метод getc пытается прочитать один байт и возращает true в случае успеха.
class IWriteFile
{
public:
virtual nat write ( const void * p, const nat size, const nat count ) = 0;
virtual bool putc ( const void * p ) = 0;
virtual void flush() = 0;
virtual ~IWriteFile() {}
};
Класс IWriteFile предназначен для записи данных. Метод write записывает информацию блоками размером size и количеством count из памяти с адресом p. Возращаемое значение - это реальное количество записанных блоков. Метод putc пытается записать один байт и возращает true в случае успеха. Метод flush сбрасывает буфер, если это было предусмотрено.
class ISeekFile
{
public:
virtual bool seek_set ( long offset ) = 0;
virtual bool seek_end ( long offset ) = 0;
virtual bool seek_cur ( long offset ) = 0;
virtual void rewind() = 0;
virtual long tell() = 0;
virtual ~ISeekFile() {}
};
Класс ISeekFile осуществляет перемещение по файлу. Методы seek_set, seek_end и seek_cur пытаются сместиться соответственно относительно начала, конца или текущей позиции на offset байт и возращают true в случае успеха. Метод rewind осуществляет переход на начало файла. Метод tell возращает текущее положение ( 0 - это начало файла ) или -1 в случае ошибки.
class IReadSeekFile : public IReadFile, public virtual ISeekFile {};
class IWriteSeekFile : public IWriteFile, public virtual ISeekFile {};
class IFile : public IReadSeekFile, public IWriteSeekFile {};
Не все файлы могут поддерживать навигацию по файлу. Те, которые это делают, должны быть производными от классов IReadSeekFile, IWriteSeekFile или IFile. Первый работает только на чтение, второй - только на запись, третий ( самый общий ) - и на чтение, и на запись. Обратите внимание, что здесь есть и множественное наследование, и виртуальные классы. Теперь рассмотрим конкретные реализации этих абстрактных классов. Класс RealFile, производный от класса IFile, является "настоящим" файлом в том смысле, что он ведёт себя точно также, как и файл из библиотеки stdio, и все его методы вызывают соответствующие функции из этой библиотеки. Вначале ( версия 2 ) я полагал, что эти функции корректно обрабатывают ситуацию, когда указатель file равен нулю, но позже я выяснил, что это не так. Поэтому в версии 2.1 во всех методах есть проверка указателя на ноль. Кроме того в классе появился метод isValid для проверки работоспособности файла.
class RealFile : public IFile
{
struct _iobuf * file;
// Запрет конструктора копии и оператора присваивания:
RealFile ( RealFile & );
void operator = ( RealFile & );
public:
RealFile(const char * filename, const char * mode);
bool isValid() const { return file != 0; }
unsigned int read (void * p, const unsigned int size, const unsigned int count);
unsigned int write(const void * p, const unsigned int size, const unsigned int count);
bool getc(void * p);
bool putc(const void * p);
bool seek_set(long offset);
bool seek_end(long offset);
bool seek_cur(long offset);
long tell();
void rewind();
void flush();
~RealFile();
};
Класс PseudoReadFile производный от класса IReadFile называется псевдофайлом, потому-что он читает данные не из файла, а из памяти, заданной указателем на массив p:
class PseudoReadFile : public IReadFile
{
const bit8 * pos;
public:
explicit PseudoReadFile ( const bit8 * p ) : pos(p) {}
nat read ( void * p, const nat size, const nat count );
bool getc ( void * p );
};
Класс PseudoReadSeekFile производный от класса IReadSeekFile помимо чтения имеет навигацию:
class PseudoReadSeekFile : public IReadSeekFile
{
CCArrRef<bit8> buf;
nat pos;
public:
explicit PseudoReadSeekFile ( CCArrRef<bit8> & p ) : buf(p), pos(0) {}
nat read(void * p, const nat size, const nat count);
bool getc(void * p);
bool seek_set(long offset);
bool seek_end(long offset);
bool seek_cur(long offset);
long tell() { return pos; }
void rewind () { pos = 0; }
};
Класс PseudoWriteFile производный от класса IWriteFile осуществляет запись в контейнер Suite<bit8> и лишён навигации.
class PseudoWriteFile : public IWriteFile
{
Suite<bit8> & suite;
// Запрет конструктора копии и оператора присваивания:
PseudoWriteFile ( PseudoWriteFile & );
void operator = ( PseudoWriteFile & );
public:
explicit PseudoWriteFile ( Suite<bit8> & p ) : suite(p) {}
nat write(const void * p, const nat size, const nat count);
bool putc(const void * p);
void flush() {}
long tell() { return pos; }
};
Класс PseudoFile может использоваться вместо трёх предыдущих.
class PseudoFile : public IFile
{
DynArray<bit8> & buf;
nat length, pos;
// Запрет конструктора копии и оператора присваивания:
PseudoFile ( PseudoFile & );
void operator = ( PseudoFile & );
public:
PseudoFile ( nat n, DynArray<bit8> & p );
nat read(void * p, const nat size, const nat count);
bool getc(void * p);
nat write(const void * p, const nat size, const nat count);
bool putc(const void * p);
void flush() {}
bool seek_set(long offset);
bool seek_end(long offset);
bool seek_cur(long offset);
void rewind() { pos = 0; }
long tell() { return pos; }
};
Класс StringWriteFile предназначен для записи данных в строку:
class StringWriteFile : public IWriteFile
{
Suite<char> suite;
// Запрет конструктора копии и оператора присваивания:
StringWriteFile ( StringWriteFile & );
void operator = ( StringWriteFile & );
public:
StringWriteFile () { suite.inc() = 0; }
nat write ( const void * p, const nat size, const nat count )
{
const nat n = size * count;
const nat k = suite.size() - 1;
suite.inc ( n );
const char * s = (const char *) p;
for ( nat i = 0; i < n; ++i ) suite[i+k] = s[i];
suite.las() = 0;
return count;
}
bool putc ( const void * p )
{
suite.las() = *(const char *) p;
suite.inc() = 0;
return true;
}
void flush() {}
const char * operator () () const
{
return suite();
}
nat size () const
{
return suite.size() - 1;
}
void clear()
{
suite.resize(1).las() = 0;
}
};
Если нужно прочитать из файла десятичное число заданное в виде текста, то можно воспользоваться следующими функциями: bool readIntDec ( IReadFile & file, char & c, int32 & i );
inline bool readIntDec ( IReadFile & file, int32 & i )
{
char c;
return readIntDec ( file, c, i );
}
bool readIntDec ( IReadFile & file, char & c, nat32 & i );
inline bool readIntDec ( IReadFile & file, nat32 & i )
{
char c;
return readIntDec ( file, c, i );
}
bool readFltDec ( IReadFile & file, char & c, real32 & f );
inline bool readFltDec ( IReadFile & file, real32 & f )
{
char c;
return readFltDec ( file, c, f );
}
bool readFltDec ( IReadFile & file, char & c, real64 & d );
inline bool readFltDec ( IReadFile & file, real64 & d )
{
char c;
return readFltDec ( file, c, d );
}
с - это последний прочитанный символ. Функция printf записывает данные в файл при помощи заданного формата. Он аналогичен стандартному, но пока ещё не все его свойства реализованы.bool printf ( IWriteFile & file, const char * format, ... ); Описание шаблонов CArrRef, Suite и DynArray находится здесь.
Исходники находятся в source.zip. Наверх |