Реализовать класс TempFileStream
для работы с временным бинарным файлом как с потоком ввода/вывода.
Класс представляет собой обёртку над набором функций f...(FILE * pf ...)
стандартной библиотеки C.
Реализовать класс TempFileStream
в соответствии с приведённым ниже интерфейсом.
//TempFileStream.hpp
#include <cstdint> // uint8_t
#include <cstdio>
enum IOState : uint8_t
{
Good = 0x00, // нет ошибок
EoF = 0x01, // при чтении достигнут конец потока
Bad = 0x02, // ошибка ввода-вывода
};
enum SeekDirection : int
{
Begin = SEEK_SET,
Current = SEEK_CUR,
End = SEEK_END,
};
class TempFileStream final
{
public:
TempFileStream();
~TempFileStream();
public:
// объекты класса stream нельзя копировать:
TempFileStream(const TempFileStream&) = delete;
TempFileStream& operator=(const TempFileStream&) = delete;
bool isOpen();
public:
uint8_t state();
void clearState();
public:
bool good();
bool eof();
bool bad();
public:
TempFileStream& open();
void close();
public:
size_t count();
public:
TempFileStream& ignore(size_t n = 1, int delim = EOF);
public:
TempFileStream& read(void* buffer, size_t size);
TempFileStream& write(const void* buffer, size_t size);
public:
int get();
TempFileStream& get(char& c);
TempFileStream& get(char* s, size_t len);
TempFileStream& put(char c);
TempFileStream& put(const char* s, size_t len);
public:
TempFileStream& print(const char* format, ...);
TempFileStream& scan(const char* format, ...);
public:
fpos_t pos();
TempFileStream& pos(fpos_t p);
long int tell();
TempFileStream& seek(long int offset, SeekDirection dir);
public:
TempFileStream& flush();
private:
// поля...
};
Для public
и protected
методов класса не допускается изменение названий,
а также типов и количества аргументов.
Однако, в приведённых фрагментах кода намеренно опущен ряд спецификаторов const
и static
.
При реализации необходимо вернуть их на место в соответствии с логикой работы класса.
Поток предоставляет доступ к временному бинарному файлу (с гарантированно уникальным именем) в режиме одновременного чтения и записи. Причем доступ к содержимому файла должен происходить побайтово.
Поток ввода / вывода должен быть однозначно связан с некоторым файлом. Ситуация, когда один объект класса TempFileStream
связан с несколькими файлами — недопустима.
Точно так же недопустима ситуация, когда с одним файлом связаны несколько объектов TempFileStream
.
Поэтому класс потока должен быть спроектирован так, чтобы предотвращать эти ситуации.
Операции ввода / вывода в файл могут закончится неудачей, поэтому необходимы механизмы обнаружения ошибочных состояний.
Один из таких механизмов — это флаги состояния потока.
Стандартная библиотека C связывает с каждым файлом два индикатора ошибок: индикатор достижения конца файла,
и индикатор всех остальных ошибок ввода-вывода.
Для описания этих двух видов ошибок создано перечисление IOState
.
Поток может перейти в то или иное ошибочное состояние, и его функционал при этом будет ограничен.
В классе TempFileStream
предусмотрены методы проверки текущего состояния потока.
При операциях ввода / вывода регулярно возникает необходимость знать количество записанных / прочитанных элементов потока (байтов, символов, и пр.).
Однако добавление в каждый метод класса функционала для информирования о количестве элементов привело бы значительному усложнению и захламлению интерфейса класса.
Поэтому с каждым объектом класса TempFileStream
связан счётчик элементов, обновляемый после каждой операции ввода / вывода.
Доступ к счётчику обеспечивается специальным методом count()
.
Интерфейс класса спроектирован так, что бы при необходимости упростить немедленный вызов count()
, state()
и других методов.
Большинство методов класса возвращают ссылку на объект TempFileStream
, т.е. на тот же самый объект, от которого этот метод был вызван.
Это позволяет организовывать цепочки вызовов:
if ( tempFile.read(buffer, 10).count() == 10 )
std::cout << "reading ok";
if ( tempFile.open().good() )
std::cout << "file is successfully opened";
// и так тоже работает, но лучше так не делать
int i;
char s[20];
bool good = tempFile
.open()
.ignore(10, '|').scan("%d", &i)
.ignore(10, '|').scan("%s", s)
.ignore(10, '|').good()
if ( good )
std::cout << "i'm lucky and have no idea why it works";
TempFileStream()
— конструктор объекта потока,
который пытается открыть временный бинарный файл с гарантированно уникальным именем в режиме одновременной записи и чтения (см. примечание 2).~TempFileStream()
— деструктор объекта потока.
Если поток был связан с временным файлом, то сбрасывает буфера ввода/вывода, закрывает файл
и удаляет временный файл.TempFileStream(const TempFileStream &) = delete
— удалённый конструктор копий (см. примечание 3).operator=(const TempFileStream &) = delete
— удалённый оператор копирования (см. примечание 3).isOpen()
— метод проверяет, связан ли данный поток каким-либо файлом.state()
— метод возвращает набор IOState
флагов, описывающих текущее состояние потока (см. примечание 4).clearState()
— метод позволяет принудительно
сбросить флаги состояния потока.good()
— метод проверяет, что у потока сброшены все индикаторы ошибок.eof()
— метод проверяет, что у потока выставлен индикатор достижения конца файла.bad()
— метод проверяет, что у потока выставлен индикатор ошибки ввода / вывода.open()
— привязывает поток к новому временному файлу с гарантированно уникальным именем в требуемом режиме (см. примечание 2).
Если объект до этого был привязан к другому файлу, то предыдущий файл корректно закрывается и удаляется (см. примечание 3).
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов state()
позволяет определить успех / неуспех операции.close()
— закрывает файл и удаляет.count()
— метод сообщает о количестве элементов потока успешно прочитанных / заспинных во время последней операции ввода / вывода (см. примечание 5).ignore(size_t n, int delim)
— метод читает из файла элементы (символы или байты) никуда не сохраняя (игнорируя) их.
Метод читает и игнорирует элементы до тех пор, пока не прочитает указанный элемент разделитель delim
, либо пока не прочитает заданное количество элементов n
.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count()
возвращает количество успешно считанных элементов.read(void * buffer, size_t size)
— метод считывает из файла
заданное количество элементов size
и сохраняет их в буфер buffer
.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count()
возвращает количество успешно считанных элементов.write(const void * buffer, size_t size)
— метод записывает в файл
size
элементов из буфера buffer
.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count()
возвращает количество успешно записанных элементов.get()
— метод считывает из потока один элемент.get(char & c)
— метод считывает из потока один элемент и сохраняет по указанной ссылке c
.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count()
возвращает количество успешно считанных элементов.get(char * s, size_t len)
— метод считывает строку из файла и сохраняет её в буффер s
длинны len
.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count()
возвращает количество успешно считанных элементов.put(char c)
— метод записывает в потока один элемент.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count()
возвращает количество успешно записанных элементов.put(const char * s, size_t len)
— метод записывает в поток строку длинны len
из буфера s
.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count()
возвращает количество успешно записанных элементов.print(const char * format, ...)
— метод осуществляет форматированный вывод в поток.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count()
возвращает количество успешно записанных элементов.scan(const char * format, ...)
— метод осуществляет форматированное чтение из потока.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count()
возвращает количество успешно распознанных и заполненных аргументов функции.pos()
— метод сообщает текущую позицию в файле в виде fpos_t
.pos(fpos_t p)
— метод устанавливает текущую позицию в файле, используя значение p
,
полученное ранее при вызове метода pos()
.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов state()
позволяет определить успех / неуспех операции.long int tell()
— метод позволяет узнать смещение от начала файла для текущей позиции.seek(long int offset, SeekDirection dir)
— метод позволяет установить текущую позицию через смещение от начала/конца файла.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов state()
позволяет определить успех / неуспех операции.flush()
— метод сбрасывает всё содержимое буферов в файл.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов state()
позволяет определить успех / неуспех операции.public
методам, класса TempFileStream
необходимо добавить в нужных местах спецификаторы static
и const
. public
и protected
методов класса, а также типы и количество аргументов в них.TempFileStream.hpp, TempFileStream.cpp
.