В этом разделе представлены классы, которые предназначены для работы с абстрактными файлами. Методы этих классов аналогичны соответствующим функциям из библиотеки 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 { CArrRef<bit8> buf; nat pos; public: explicit PseudoReadSeekFile ( CArrRef<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. Наверх |