Шаг 518.
Библиотека STL. Ввод-вывод с использованием потоковых классов. Классы потоковых буферов. Пользовательские буферы вывода (продолжение)

    На этом шаге мы продолжим изучение этого вопроса.

    Чтобы конструировать потоковые буферы было проще, рекомендуется также реализовать специальный класс потока данных, назначение которого сводится к передаче аргументов конструктора соответствующему потоковому буферу. В следующем примере показано, как это делается. В данном случае определяется класс потокового буфера, который инициализируется файловым дескриптором, используемым для записи символов функцией write() (низкоуровневая функция ввода-вывода в системах семейства UNIX). Также определяется класс, производный от ostream, - он поддерживает потоковый буфер, которому передается файловый дескриптор.

// oubuf2.hpp
#include <iostream>
#include <streambuf>
#include <cstdio>

extern "C" {
    int write (int fd, const char* buf, int num);
}

class fdoutbuf : public std::streambuf {
  protected:
    int fd;    // Файловый дескриптор
  public:
    // Конструктор
    fdoutbuf (int _fd) : fd(_fd) {
    }
  protected:
    // Запись одного символа
    virtual int_type overflow (int_type c) {
        if (c != EOF) {
            char z = c;
            if (write (fd, &z, 1) != 1) {
                return EOF;
            }
        }
        return c;
    }
    // Запись нескольких символов
    virtual
    std::streamsize xsputn (const char* s,
                            std::streamsize num) {
        return write(fd,s,num);
    }
};

class fdostream : public std::ostream {
  protected:
    fdoutbuf buf;
  public:
    fdostream (int fd) : std::ostream(0), buf(fd) {
        rdbuf(&buf);
    }
};

    Потоковый буфер также реализует функцию xsputn(), позволяющую предотвратить вызов overflow() для каждого символа при отправке в буфер последовательности символов. Функция записывает всю последовательность символов в файл, заданный дескриптором fd, за один вызов. Функция xsputn() возвращает количество успешно выведенных символов. Пример:

//---------------------------------------------------------------------------

#include <vcl.h>
#include <iostream>
#include "outbuf2.hpp"

#include <conio.h>   //необходимо для getch()

#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
using namespace std;

std::string ToRus(const std::string &in)
{
  char *buff = new char [in.length()+1];
  CharToOem(in.c_str(),buff);
  std::string out(buff);
  delete [] buff;
  return out;
}

int main (int argc, char* argv[])
{
  fdostream out(1);  // Поток с буфером, записывающим по дескриптору 1
  out << ToRus("31 в шестнадцатеричной системе счисления: ") 
      << std::hex << 31 << std::endl;


  getch();
  return 0;
}

//---------------------------------------------------------------------------
Текст этого примера можно взять здесь.

    Результат работы приложения выглядит так:


Рис.1. Результат работы приложения

    Программа создает выходной поток данных, инициализируемый дескриптором файла 1. По действующим правилам этот дескриптор соответствует стандартному каналу вывода. Следовательно, в данном примере символы будут просто направляться в стандартный выходной поток данных. В аргументе конструктора также могут использоваться другие дескрипторы (например, дескриптор файла или сокета).

    На следующем шаге мы закончим изучение этого вопроса.




Предыдущий шаг Содержание Следующий шаг