Пятница, 29.03.2024
Меню сайта
Вход на сайт
Логин:
Пароль:
Поиск
Статистика
Рейтинг@Mail.ru Яндекс.Метрика
Реклама
C++ Delphi Прочее
Буферизация
При задании операций ввода/вывода мы никак не касались типов файлов, но ведь не все устройства можно рассматривать одинаково с точки зрения стратегии буферизации. Например, для ostream, подключенного к символьной строке, требуется буферизация другого вида, нежели для ostream, подключенного к файлу. С этими проблемами можно справиться, задавая различные буферные типы для разных потоков в момент инициализации (обратите внимание на три конструктора класса ostream). Есть только один набор операций над этими буферными типами, поэтому в функциях ostream нет кода, их различающего. Однако функции, которые обрабатывают переполнение сверху и снизу, виртуальные. Этого достаточно, чтобы справляться с необходимой в данное время стратегией буферизации. Это также служит хорошим примером применения виртуальных функций для того, чтобы сделать возможной однородную обработку логически эквивалентных средств с различной реализацией.Описание буфера потока в выглядит так:

Code
struct streambuf { // управление буфером потока  

char* base; // начало буфера  
char* pptr; // следующий свободный char  
char* qptr; // следующий заполненный char  
char* eptr; // один из концов буфера  
char alloc; // буфер, выделенный с помощью new  

// Опустошает буфер:  
// Возвращает EOF при ошибке и 0 в случае успеха  
virtual int overflow(int c =EOF);  

// Заполняет буфер  
// Возвращет EOF при ошибке или конце ввода,  
// иначе следующий char  
virtual int underflow();  

int snextc() // берет следующий char  
{  
return (++qptr==pptr) ? underflow() : *qptr&0377;  
}  

// ...  

int allocate() // выделяет некоторое пространство буфера  

streambuf() { /* ... */}  
streambuf(char* p, int l) { /* ... */}  
~streambuf() { /* ... */}  
};

Обратите внимание, что здесь определяются указатели, необходимые для работы с буфером, поэтому обычные посимвольные действия можно определить (только один раз) в виде максимально эффективных inline- функций. Для каждой конкретной стратегии буферизации необходимо определять только функции переполнения overflow() и underflow().

Code
struct filebuf : public streambuf {  

int fd; // дескриптор файла  
char opened; // файл открыт  

int overflow(int c =EOF);  
int underflow();  

// ...  

// Открывает файл:  
// если не срабатывает, то возвращает 0,  
// в случае успеха возвращает "this"  
filebuf* open(char *name, open_mode om);  
int close() { /* ... */ }  

filebuf() { opened = 0; }  
filebuf(int nfd) { /* ... */ }  
filebuf(int nfd, char* p, int l) : (p,l) { /* ... */ }  
~filebuf() { close(); }  
};  

int filebuf::underflow() // заполняет буфер из fd  
{  
if (!opened || allocate()==EOF) return EOF;  

int count = read(fd, base, eptr-base);  
if (count < 1) return EOF;  

qptr = base;  
pptr = base + count;  
return *qptr & 0377;  
}
C++ 3637 05.01.2010
Материалы по теме: