Класс IFile

В этом разделе представлены классы, которые предназначены для работы с абстрактными файлами. Методы этих классов аналогичны соответствующим функциям из библиотеки 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; }
};

Если нужно прочитать из файла десятичное число заданное в виде текста, то можно воспользоваться следующими функциями:

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 );
}

с - это последний прочитанный символ.

Следующие функции записывают в файл числа в текстовом десятичном виде. Две функции writeIntDec записывают в файл целое число ( знаковое и беззнаковое ). Параметр dig задаёт минимальное к-во выводимых десятичных разрядов ( 1 <= dig <= 10 ). В случае необходимости число будет дополнено слева нулями. Функция writeFltDec записывает в файл число с плавающей точкой. Функция writeExpDec записывает в файл число с плавающей точкой в экспотенциальном виде. Параметр prec задаёт к-во дробных десятичных разрядов ( 0 <= prec <= 310 ). Если параметр plus = true, то для неотрицательных чисел вначале пишется знак +. Функция writeStr записывает в файл строку, которая заканчивается нулём.

bool writeIntDec ( IWriteFile & file, int32 i, int32 dig = 1, bool plus = false );

bool writeIntDec ( IWriteFile & file, nat32 i, int32 dig = 1, bool plus = false );

bool writeFltDec ( IWriteFile & file, real64 d, nat32 prec, bool plus = false );

bool writeExpDec ( IWriteFile & file, real64 d, nat32 prec, bool plus = false );

bool writeStr ( IWriteFile & file, const char * str );

Описание шаблонов CArrRef, Suite и DynArray находится здесь.
Описание типов bit8, int32 и nat32 находится здесь.

Исходники находятся в source.zip.

Наверх