Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Введение в С++. Страуструп..doc
Скачиваний:
63
Добавлен:
02.05.2014
Размер:
3.46 Mб
Скачать

Istream - шаблон типа smanip, а smanip - двойник для ioss.

Некоторые из стандартных манипуляторов, предлагаемых поточной

библиотекой, описаны ниже. Отметим,что программист может определить новые

необходимые ему манипуляторы, не затрагивая определений istream,

ostream, OMANIP или SMANIP.

Идею манипуляторов предложил А. Кениг. Его вдохновили процедуры

разметки (layout ) системы ввода-вывода Алгола68. Такая техника имеет

много интересных приложений помимо ввода-вывода. Суть ее в том, что

создается объект, который можно передавать куда угодно и который

используется как функция. Передача объекта является более гибким

решением, поскольку детали выполнения частично определяются создателем

объекта, а частично тем, кто к нему обращается.

10.4.2.1 Стандартные манипуляторы ввода-вывода

Это следующие манипуляторы:

// Simple manipulators:

ios& oct(ios&); // в восьмеричной записи

ios& dec(ios&); // в десятичной записи

ios& hex(ios&); // в шестнадцатеричной записи

ostream& endl(ostream&); // добавить '\n' и вывести

ostream& ends(ostream&); // добавить '\0' и вывести

ostream& flush(ostream&); // выдать поток

istream& ws(istream&); // удалить обобщенные пробелы

// Манипуляторы имеют параметры:

SMANIP<int> setbase(int b);

SMANIP<int> setfill(int f);

SMANIP<int> setprecision(int p);

SMANIP<int> setw(int w);

SMANIP<long> resetiosflags(long b);

SMANIP<long> setiosflags(long b);

Например,

cout << 1234 << ' '

<< hex << 1234 << ' '

<< oct << 1234 << endl;

напечатает

1234 4d2 2322

и

cout << setw(4) << setfill('#') << '(' << 12 << ")\n";

cout << '(' << 12 << ")\n";

напечатает

(##12)

(12)

Не забудьте включить файл <iomanip.h>, если используете манипуляторы с

параметрами.

10.4.3 Члены ostream

В классе ostream есть лишь несколько функций для управления выводом,

большая часть таких функций находится в классе ios.

class ostream : public virtual ios {

//...

public:

ostream& flush();

ostream& seekp(streampos);

ostream& seekp(streamoff, seek_dir);

streampos tellp();

//...

};

Как мы уже говорили, функция flush() опустошает буфер в выходной поток.

Остальные функции используются для позиционирования в ostream при

записи. Окончание на букву p указывает, что именно позиция используется

при выдаче символов в заданный поток. Конечно эти функции имеют смысл,

только если поток присоединен к чему-либо, что допускает

позиционирование, например файл. Тип streampos представляет позицию символа

в файле, а тип streamoff представляет смещение относительно позиции,

заданной seek_dir. Все они определены в классе ios:

class ios {

//...

enum seek_dir {

beg=0, // от начала файла

cur=1, // от текущей позиции в файле

end=2 // от конца файла

};

//...

};

Позиции в потоке отсчитываются от 0, как если бы файл был массивом из

n символов:

char file[n-1];

и если fout присоединено к file, то

fout.seek(10);

fout<<'#';

поместит # в file[10].

10.4.4 Члены istream

Как и для ostream, большинство функций форматирования и управления

вводом находится не в классе iostream, а в базовом классе ios.

class istream : public virtual ios {

//...

public:

int peek()

istream& putback(char c);

istream& seekg(streampos);

istream& seekg(streamoff, seek_dir);

streampos tellg();

//...

};

Функции позиционирования работают как и их двойники из ostream.

Окончание на букву g показывает, что именно позиция используется при

вводе символов из заданного потока. Буквы p и g нужны, поскольку

мы можем создать производный класс iostreams из классов ostream и

istream, и в нем необходимо следить за позициями ввода и вывода.

С помощью функции peek() программа может узнать следующий символ,

подлежащий вводу, не затрагивая результата последующего чтения. С

помощью функции putback(), как показано в $$10.3.3, можно вернуть

ненужный символ назад в поток, чтобы он был прочитан в другое время.

10.5 Файлы и потоки

Ниже приведена программа копирования одного файла в другой. Имена

файлов берутся из командной строки программы:

#include <fstream.h>

#include <libc.h>

void error(char* s, char* s2 ="")

{

cerr << s << ' ' << s2 << '\n';

exit(1);

}

int main(int argc, char* argv[])

{

if (argc != 3) error("wrong number of arguments");

ifstream from(argv[1]);

if (!from) error("cannot open input file",argv[1]);

ostream to(argv[2]);

if (!to) error("cannot open output file",argv[2]);

char ch;

while (from.get(ch)) to.put(ch);

if (!from.eof() || to.bad())

error("something strange happened");

return 0;

}

Для открытия выходного файла создается объект класса ofstream -

выходной поток файла, использующий в качестве аргумента имя файла.

Аналогично, для открытия входного файла создается объект класса

ifstream - входной файловый поток, также использующий в качестве

аргумента имя файла. В обоих случаях следует проверить состояние

созданного объекта, чтобы убедиться в успешном открытии файла, а

если это не так, операции завершатся не успешно, но корректно.

По умолчанию ifstream всегда открывается на чтение, а ofstream

открывается на запись. В ostream и в istream можно использовать

необязательный второй аргумент, указывающий иные режимы открытия:

class ios {

public:

//...

enum open_mode {

in=1, // открыть на чтение

out=2, // открыть как выходной

ate=4, // открыть и переместиться в конец файла

app=010, // добавить

trunc=020, // сократить файл до нулевой длины

nocreate=040, // неудача, если файл не существует

noreplace=0100 // неудача, если файл существует

};

//...

};

Настоящие значения для open_mode и их смысл вероятно будут зависеть

от реализации. Будьте добры, за деталями обратитесь к руководству по

вашей библиотеке или экспериментируйте. Приведенные комментарии

могут прояснить их назначение. Например, можно открыть файл с условием,

что операция открытия не выполнится, если файл уже не существует:

void f()

{

ofstream mystream(name,ios::out|ios::nocreate);

if (ofstream.bad()) {

//...

}

//...

}

Также можно открыть файл сразу на чтение и запись:

fstream dictionary("concordance", ios::in|ios::out);

Все операции, допустимые для ostream и ostream, можно применять к

fstream. На самом деле, класс fstream является производным от iostream,

который является, в свою очередь, производным от istream и ostream.

Причина, по которой информация по буферизации и форматированию для

ostream и istream находится в виртуальном базовом классе ios, в том,

чтобы заставить действовать всю эту последовательность производных

классов. По этой же причине операции позиционирования в istream и

ostream имеют разные имена - seekp() и seekg(). В iostream есть

отдельные позиции для чтения и записи.