Сапа
Здесь может быть ваша реклама
|

 Глава 9. Потоки ввода-вывода

Глава 9. Потоки ввода-вывода

До сих пор в программных примерах мы пользовались только функциями стандартной библиотеки С. Однако в C++ имеются собственные средства, основанные на принципах классовой модели. Другими словами, в исполнительной библиотеке C++ имеется набор классов для управления вводом-выводом.

В отличие от функций буферизованного ввода-вывода С (таких, как print f и scanf, не выполняющих никаких проверок на соответствие аргументов форматной строке) классы потоков C++ безопасны в отношении типа. Ввод-вывод использует механизм перегрузки операций, гарантирующий вызов нужной функции-операции для указанного типа данных. Это главное преимущество потоков языка C++.

Классы потоков

К классам потоков относятся следующие:

  • Класс streambuf управляет буфером потока, обеспечивая базовые операции заполнения, опорожнения, сброса и прочих манипуляций с буфером.
  • Класс ios является базовым классом потоков ввода-вывода.
  • Классы istream и ostream — производные от ios и обеспечивают работу потоков соответственно ввода и вывода.
  • Класс iоstream является производным от двух предыдущих и предусматривает функции как для ввода, так и для вывода.
  • Классы ifstream, of stream и f stream предназначены для управления файловым вводом-выводом.
  • Классы istrstream и ostrstream управляют резидентными потоками (форматированием строк в памяти). Это устаревшая методика,оставшаяся в C++Builder в качестве пережитка.

Для работы с потоками вам потребуется включить в программу заголовочный файл iostream.h. Кроме того, может потребоваться подключить файлы fstream.h (файловый ввод-вывод), iomanip.h (параметризованные манипуляторы) и strstream.h (форматирование ь памяти).

Предопределенные потоки

Библиотека ввода-вывода C++ предусматривает четыре предопределенных объекта-потока, связанных со стандартными входным и выходным устройствами. Ниже дана сводка этих объектов.

Таблица 9.1. Предопределенные объекты-потоки C++

Имя

Класс

Описание

cin

istream

Ассоциируется со стандартным вводом (клавиатурой).

cout

ostream

Ассоциируется со стандартным выводом (экраном).

cerr

ostream

Ассоциируется со стандартным устройством ошибок (экраном) без буферизации.

clog

ostream

Ассоциируется со стандартным устройством ошибок (экраном)с буферизацией.

 

Операции извлечения и передачи в поток

Основными классами ввода-вывода C++ являются istream и ostream. Первый из них перегружает операцию правого сдвига (>>), которая служит в нем для ввода данных и называется операцией извлечения из потока. Класс ostream перегружает соответственно операцию левого сдвига(<<); она применяется для вывода и называется операцией передачи в поток.

Примечание

Нужно сказать, что стандартной русской терминологии как таковой в C++ не существует. Каждый изобретает свою собственную; иногда удачно, иногда — нет.

Вот простейшие операторы ввода и. вывода на стандартных потоках:

#include <iostream.h>

int main()

{

char name [ 8.0] ;

cout<< "Enter your name: ";

cin>> name;

cout <<"Hello " << name << "!";

return 0;

}

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

Перегруженные операции для встроенных типов

Классы istream и ostream перегружают операции соответственно извлечения и передачи в поток для всех встроенных типов. Это позволяет единообразно применять эти операции для чтения и вывода символов, целых, вещественных чисел (т. е. с плавающей точкой) и строк. Вот небольшая иллюстрация, где попутно показан еще простейший прием проверки на ошибку при вводе:

#include <iostream.h>

void check(void) {

if (!cin.good())

{

// Либо просто if (!cin) {

cout << "Error detected!";

exit (1);

}

int main(void)

{

double d;

long 1;

cout << "Enter a floating point value: ";

cin >> d;

check () ;

cout << "You entered: " << d << 'n';

cout << "Enter an integer value: ";

cin >> 1;

check () ;

cout << "You entered: " << 1 << 'n';

return 0;

}

Примечание

Операции извлечения и передачи в поток (соответственно для классов istream и ostream) можно перегрузить таким образом, чтобы можно было применять их для ввода или вывода объектов класса, определенного пользователем. Приведенный ниже пример демонстрирует эту методику. Вообще-то в подобных случаях совершенно необходимо предусмотреть детектирование и обработку ошибок ввода, но здесь мы этого не сделали.

#include <iostream.h>

class Point { int x, у;

public:

Point(int xx = 0, int yy = 0) {

x = xx; у = yy;

}

friend istream &operator>>(istream&, Points);

friend ostream &operator“(ostream&, Points);

};

istream &operator”(istream &is, Point &p)

//

// При вводе точка представляется просто парой чисел,

// разделенных пробелом.

// is >> р.х> р.у;

return is;

}

ostream &operator<<(ostream &os.Point &p) {

//

// Вывод в виде (х, у).

//

os<< ' ( '<< р. х<< ", "<< р. у<<') ' ;

return os;

}

int main() {

Point р;

cout<< "Enter point coordinates: ";

cin>> р;

cout<< "The point values are " << р;

return 0;

}

Форматирование

Библиотека ввода-вывода предусматривает три способа форматирования: посредством вызова форматирующих функций-элементов, с помощью манипуляторов или путем установки или сброса флагов потока.

Форматирующие функции-элементы

Эти функции являются элементами класса ios и перегружены таким образом, чтобы можно было либо читать, либо устанавливать значение соответствующего атрибута потока. Если аргумент в вызове отсутствует, функция возвращает текущее значение атрибута. Если аргумент указан, функция устанавливает новое и возвращает предыдущее значение атрибута.

long width(long)

Эта функция предназначена для чтения или установки атрибута ширины поля.

  • Применяемая ко входному потоку, функция позволяет задать максимальное число вводимых символов.
  • На выходном потоке функция задает минимальную ширину поля вывода.
  • Если действительное поле вывода меньше установленной ширины, выводятся дополнительные заполняющие символы. Символ заполнения определяется специальным атрибутом потока.
  • Если действительное поле вывода больше установленной ширины, ее значение игнорируется.
  • Значением ширины по умолчанию является 0 (ширина поля определяется выводимыми данными).
  • Ширина поля сбрасывается в 0 после каждой передачи в поток.

char fill(char)

Функция позволяет прочитать или установить текущий символ заполнения.

По умолчанию символ заполнения — пробел.

long precision(long)

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

  • Точность по умолчанию равна шести цифрам.
  • Если установлен флаг scientific или fixed, точность задает число цифр после десятичной точки.
  • Если ни один из этих флагов не установлен, точность задает общее число значащих цифр.

Пример

Ниже приводится программа, демонстрирующая форматирование потока с помощью функций-элементов класса ios.

Листинг 9.1. Демонстрация форматирующих функций потока

///////////////////////////////////////////////

// Format.срр: Форматирующие функции-элементы ios.

//

#include <iostream.h>

#pragma hdrstop

#include <condefs.h>

#pragma argsused

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

{

//

// Ширина поля при вводе и выводе.

//

cnar sir [16];

cout<< "Enter something: ";

cin.width(16); // Ввод не более 15 символов. cin>> str;

cout.width(32); // Вывести в поле шириной 32. cout<< str<< "nn";

//

// Заполняющий символ и ширина поля. Ширина сбрасывается

// после каждой операции, поэтому она устанавливается

// для каждого числа.

//

int h = 7, m = 9, s = 0; // Выводятся в виде hh:mm:ss.

cout.fill('0'); cout << "Time is ";

cout.width (2); cout << h << ' : ' ; cout.width (2) ;

cout<< m<< ' : ' ;

cout.width (2) ;

cout<< s<< ".nn";

cout.fill (' '); // Восстановить пробел.

//

// Точность.

//

double d = 3.14159265358979;

float f = 27182.81828;

cout.precision (5);

cout << f << 'n'; . // Выводит "27183" .

cout << d << 'n'; ' // Выводит "3.1416".

cout .precision (4) ;

cout << f << 'n'; // Выводит "2.718е+04".

cout.setf(ios::fixed); // Установить флаг fixed.

cout<< f<<'n'; // Выводит "27182.8184".

return 0;

}

Манипуляторы

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

Ниже приводится сводка имеющихся манипуляторов, как простых, так и параметризованных. Они Перечислены в алфавитном порядке.

Таблица 9.2. Простые и параметризованные манипуляторы

Манипулятор

Описание

dec

Задает десятичную базу преобразования.

end1

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

ends

Передает в поток символ завершающего строку нуля.

flush

Сбрасывает выходной поток.

hex

Задает шестнадцатеричную базу преобразования.

lock(ios Sir)

Блокирует дескриптор файла потока ir.

oct

Задает восьмеричную базу преобразования.

resetiosflags(int f)

Сбрасывает флаги, биты которых установлены в f.

setbase(int b)

Устанавливает базу преобразования (0, 8, 10 или 16).

setiosflags(int f)

Устанавливает флаги, биты которых установлены в f.

setfill(int c)

Задает символ заполнения (аналогичен функции

fiilO).

setprecision(long p)

Задает точность (аналогичен функции precision ()).

setw(iong w)

Задает ширину поля (аналогичен функции width ()).

lunlock(ios &ir)

Разблокирует дескриптор файла для потока ir.

ws

Исключает начальные пробельные символы.

 

Вот пример использования некоторых манипуляторов (мы создали один свой собственный):

Листинг 9.2. Форматирование с помощью манипуляторов

/////////////////////////////////////////////////

// Manip.cpp: Демонстрация некоторых манипуляторов.

//

#include <iomanip.h>

#pragma hdrstop

#include <condefs.h>

//////////////////////////////////////////////////

// Манипулятор, определенный пользователем - звонок.

//

ostream shell(ostream &os)

{

return os<< 'a';

#pragma argsused

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

{

cout “ bell; // Тестирование манипулятора bell.

//

// Манипуляторы базы преобразования.

//

long 1 = 123456;

cout<< "Hex: "<< hex<< 1<< end1

<<"Oct: "<< oct<< 1<< end1

<< "Dec: " << dec << 1 << end1;

//

// Параметризованные манипуляторы.

//

int h=12, m=5, s=0; // To же, что в примере

// Format.cpp. cout << "The time is " << setfill('0')

<< setw(2) << h << ':'

<< setw(2) << m << ':'

<< setw(2) << s << setfillC ') << end1;

return 0;

}

Как видите, очень несложно определить свой собственный простой манипулятор. Это всего лишь функция, возвращающая ссылку на переданный ей в параметре поток.

Примечание

Создать параметризованный манипулятор не так просто. Существуют различные способы сделать это, но наиболее очевидный из них — реализация манипулятора через класс эффектора. Идея состоит вот в чем. Нужно определить для манипулятора собственный класс с конструктором, принимающим нужные параметры, •и перегрузить для этого класса операцию передачи (извлечения) соответствующего потока. После этого конструктор можно вызывать в качестве параметризованного манипулятора. Создается временный объект, который выводится в поток перегруженной операцией и удаляется.Ниже показан манипулятор, который выводит в поток свой аргумент типа unsigned в двоичной форме.

#include <iostream.h>

// Класс эффектора.

class Bin {

int val;

public:

Bin(unsigned arg) { val = arg; }

friend ostream &operator“(ostreams. Bin);

};

// Вывод числа в двоичной форме.

ostream &ooerator<<(ostream &os. Bin b) {

int cb = 1; // Контрольный бит для отсчета циклов.

do {

if (b.val <0) // Если val < 0, то старший бит = 1. os << 1;

else

os<< 0;

} while (b.vai<<= 1, cb<<= 1) ;

return os;

}

int main ()

(

unsigned n = Ox00ff0f34;

cout<< "Some binary: "<< Bin(n)<< end1;

return 0;

}

C++Builder, программы, электронные книги, раскрутка, оптимизация

Рис. 9.1Манипулятор, выводящий свой аргумент в двоичной форме

Форматирующие флаги

Флаги управления форматированием являются битовыми полями, хранящимися в переменной типа fmtflags (псевдоним int). Для их чтения и/или модификации могут применяться следующие функции-элементы класса ics:

  • int flags (), int flags (int). Без параметра возвращает текущее состояние флагов. При указанном параметре устанавливает новые значения флагов и возвращает их прежнее состояние.
  • int setf(int), long setf(int, int). Первая форма устанавливает флаги, биты которых установлены в параметре. Вторая форма модифицирует флаги, биты которых установлены во втором параметре. Значения этих флагов задаются первым параметром. Возвращает прежнее состояние всех флагов.
  • void unsetf(int). Сбрасывает флаги, биты которых установлены в параметре.

Помимо функций, для управления флагами можно пользоваться манипуляторами setiosflags (аналог setf() с одним параметром) и reset-iosflags (аналог unsetf ()).

В таблице 9.3 описаны форматирующие флаги потоков.

Таблица 9.3. Форматирующие флаги класса ios

Флаг

Описание

internal

Если установлен, при выводе чисел знак выводится на левом краю поля вывода, а само число выравнивается по правому краю поля. Промежуток заполняется текущим символом заполнения.

dec

Устанавливает десятичное представление чисел. Принимается по умолчанию.

oct

Устанавливает восьмеричное представление чисел.

hex

Устанавливает шестнадцатеричное представление чисел.

showbase

Если установлен, то при восьмеричном и шестнадцатеричном представлении чисел выводит индикатор основания (0 для восьмеричных и Ох для шестнадцатеричных чисел).

showpoint

Если установлен, для вещественных чисел всегда выводится десятичная точка.

uppercase

Если установлен, шестнадцатеричные цифры от А до F, а также символ экспоненты Е выводятся в верхнем регистре.

boolalpfa

Если установлен, булевы значения выводятся как слова “true/false”. В противном случае они представляются соответственно единицей и нулем.

showpos

Выводит + для положительных чисел.

scientific

Если установлен, вещественные числа выводятся в научной (экспоненциальной) нотации.

fixed

Если установлен, вещественные числа выводятся в десятичном формате (с фиксированной точкой).

unitbuf

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

 

Несколько замечаний относительно перечисленных в таблице флагов.

  • Флаги left, right и internal являются взаимоисключающими. В данный момент времени может быть установлен только один из них.
  • Взаимоисключающими являются также флаги dec, oct и hex.
  • При модификации базы представления в качестве второго параметра setf() можно использовать константу ios: :basefield.
  • При модификации выравнивания в поле можно аналогичным образом использовать константу ios: :adjustfield.
  • При модификации формы представления (нотации) чисел с плавающей точкой можно использовать константу ios : : floatfield. Ниже мы приводим листинг программы, демонстрирующей применение различных флагов форматирования.

Примечание

Имена перечисленных выше флагов и других констант принадлежат к области действия класса ios. Вне этого класса нужно либо воспользоваться разрешением области действия (ios : : scientific), либо обращаться к ним, как к элементам существующего объекта (cout. scientific). Мы поедпочитаем первый способ.

Листинг 9.3. форматирующие флаги потоков

////////////////////////////////////////////////////

// Flags.срр: Форматирующие флаги потоков.

//

#include <iostream.h>

#include <iomanip.h> #pragma hdrstop

#include <condefs.h>

#pragma argsused

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

{

//

// Демонстрация флага skipws. Если его сбросить, то при

// наличии начальных пробелов при вводе возникает ошибка.

//

long 1;

cout<< "Enter an integer: ";

cin.unsetf(ios::skipws);

cin >> 1;

if (cin) // При ошибке потока

cin == NULL. cout<< "You entered "<< 1<< endl;

else {

cout << "Incorrect input."<< endl;

cin.clear (); // Обнуление битов ошибки.

} cout<<endl;

//

// Демонстрация флагов основания и знака.

// Задается основание 16, вывод индикатора и знака +.

//

1 = 8191;

cout.setf(ios::hex, ios::basefield);

cout.setf(ios::showbase | ios::showpos);

cout << "hex: " <<1 << oct // Изменим основание

<< " oct: "<< 1 << dec // манипулятором.

<< " dec: " << 1 << endl;

cout << endl;

//

// Демонстрация флагов формата вещественных чисел.

//

double dl = 1.0е9, d2 = 34567.0;

cout <<"Default: " << dl << " "<<d2 << end1;

// Вывод десятичной точки. cout.setf(ios::showpoint);

cout << "Decimal: " << dl<< " " << d2 << endl;

// Нотация с фиксированной точкой.

// Заодно сбросим вывод знака +.

cout.setf(ios::fixed, ios::floatfield | ios::showpos);

cout << "Fixed: " << dl << " " << d2 << endl;

cout<< endl;

//

// Вывод булевых значений как "true/false".

//

bool b = true;

cout.setf(ios::boolalpha) ;

cout << "Boolean values:" << b << '' << !b endl;

return 0;

}

C++Builder, программы, электронные книги, раскрутка, оптимизация

Рис. 9.2Демонстрация флагов форматиоования потока

Состояние потока

Состояние объекта класса ios (и производных от него) содержится в его закрытом элементе _state в виде набора битов. Следующая таблица перечисляет имеющиеся биты состояния потока.

Таблица 9.4. Биты состояния потока

Бит

Описание

goodbit

С потоком все в порядке (на самом деле это не какой-то бит, а 0 — отсутствие битов ошибки).

eofbit

Показывает, что достигнут конец файла.

failbit

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

badbit

Индицирует серьезную ошибку потока, связанную обычно с буферными операциями или аппаратурой. Скорее всего, поток далее использовать невозможно.

 

Для опроса или изменения состояния потока в классе ios имеется ряд функций и операций.

  • int rdstate() ; Возвращает текущее состояние.
  • bool eof() ; Возвращает true, если установлен eofbit.
  • bool good () ; Возвращает true, если не установлен ни один из битов ошибки.
  • bool fail () ; Возвращает true, если установлен failbit или bad-bit.
  • bool bad() ; Возвращает true, если установлен badbit.
  • void clear (int =0); Сбрасывает биты ошибки (по умолчанию) или устанавливает состояние потока в соответствии с аргументом.
  • void setstate(int) ; Устанавливает состояние битов ошибки с соответствии с аргументом.
  • operator void*() ; Возвращает нулевой указатель, если установлен какой-либо из битов ошибки.
  • bool operator! () ; Возвращает true, если установлен какой-либо из битов ошибки.

Примечание

Функция operator void*() неявно вызывается, если поток сравнивается с нулем (как cin в примере из листинга),

Файловые потоки

Файловые потоки библиотеки ввода-вывода реализуют объектно-ориентированную методику работы с дисковыми файлами. Имеется три класса таких потоков:

  • ifstream специализирован для ввода из дисковых файлов.
  • of stream специализирован для записи дисковых файлов.
  • fstream управляет как вводом, так и записью на диск.

Эти классы выводятся соответственно из istream, ostream и iostream. Таким образом, они наследуют все их функциональные возможности (перегруженные операции << и>>” для встроенных типов, флаги форматирования и состояния, манипуляторы и т. д.).

Чтобы работать с файловым потоком, нужен, во-первых, объект потока, а во-вторых, открытый файл, связанный с этим объектом.

Конструирование объекта потока

Каждый из трех классов файловых потоков имеет четыре конструктора.

  • Конструктор, создающий объект без открытия файла:

ifstream () ;

of stream();

fstream () ;

  • Конструктор, создающий объект, открывающий указанный файл и закрепляющий этот файл за потоком. Аргументами являются имя файла, режим открытия и режим защиты (в Windows не используется):

if stream(const char *name,

int mode = ios::in, long prot = 0666);

ofstream(const char *name,

int mode = ios::out, long prot = 0666);

fstream (const char *name, int mode, long prot = 0666);

  • Конструктор, создающий объект и связывающий с ним уже открытый файл. В качестве аргумента передается дескриптор файла:

ifstreamfint file);

ofstream(int file);

fstream (int file) ;

  • Конструктор, создающий объект и связывающий с ним уже открытый файл; объект ассоциируется указанным буфером:

ifstream(int file, char *buf, int len)

of stream(int file, char *buf, int len)

fstream (int file, char *buf, int len)

Режимы открытия файла

Параметр mode, который имеет вторая форма конструктора, задает режим открытия файла. Для значений параметра класс ios определяет символические константы, перечисленные в таблице 9.5.

Таблица 9.5. Константы класса ios для режимов открытия файла

Константа

Описание

арр

Открытие для записи в конец файла.

ate

При открытии позиционирует указатель на конец файла.

binary

Файл открывается в двоичном (не текстовом) режиме.

in

Файл открывается для ввода.

out

Файл открывается для вывода.

trunc

Если файл существует, его содержимое теряется.

 

Константы можно комбинировать с помощью поразрядного OR. Для конструкторов классов if stream и ofstream параметр mode имеет значения по умолчанию — соответственно ios : : in и ios : : out.

Закрытие файла

В классах файловых потоков имеется функция close (), которая сбрасывает содержимое потока и закрывает ассоциированный с ним файл.

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

При ошибке закрытия файла устанавливается флаг failbit.

Примеры файловых потоков

Следующий пример (листинг 9.4) демонстрирует различные режимы и способы открытия потока.

Листинг 9.4. Примеры открытия файловых потоков

/////////////////////////////////////////////////////////

// Filemode.срр: Режимы открытия файлов.

//

#include <f stream .,h>

#include <string.h>

#pragma hdrstop

#include <condefs.h>

char *data[] = {"It's the first line of test data.",

"Second ,line.",

"Third line.",

"That's enough!"};

//

// Функция для распечатки содержимого файла. //

int Print(char *fn) {

char buf[80] ;

ifstream ifs(fn) ;

if (!ifs) {

cout <<fn<< " - Error reading file." << endl;

return -1;

} while (ifs) {

ifs.getline(buf, sizeof(buf)) ;

if (ifs)

cout << buf<< end1;

} return 0;

}

#pragma argsused

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

{

char name[]= "Newfile.txt";

fstream fs(name, ios::in);

if (fs) { // Файл уже существует. cout “ name “ " - File already exists." << endl;

} else { // Создать новый файл.

cout<< name<< " - Creating new file."<< endl;

fs.open(name, ios::out);

for (int i=0; i<3; i++) fs << data[i] << endl;

}

fs.close () ;

cout << end1;

//

// Файл либо уже существовал, либо мы его только что

// создали. Распечатаем его.

// Print(name);

cout << endl;

//

// Допишем строку в конец файла.

// fs.open(name, ios::app);

if (rs) {

fs M<< data[3]<< endl;

fs.close ();

} Print(name);

return 0;

}

C++Builder, программы, электронные книги, раскрутка, оптимизация

Рис. 9.3Результат работы программы Filemode

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

Бесформатный ввод-вывод

До сих пор речь у нас шла почти исключительно о вводе-выводе с использованием операций извлечения/передачи данных. Эти операции перегружены для всех встроенных типов и выполняют соответствующие преобразования из внутреннего представления данных в текстовое и из текстового во внутреннее (машинное).

Однако в библиотеке C++ имеется немало функций бесформатного ввода-вывода, которые часто применяют для чтения и записи двоичных (не-текстовых) файлов.

Двоичный режим ввода-вывода

Двоичный режим открытия файла (с установленным битом binary) означает, что никакой трансляции данных при передаче из файла в поток и обратно производиться не будет. Речь здесь идет не о форматных преобразованиях представления данных. При текстовом режиме (он принимается по умолчанию) при передаче данных между файлом и потоком производится замена пар символов CR/LF на единственный символ LF (' n ') и наоборот. Это происходит до преобразований представления, которые выполняются операциями извлечения/передачи. Двоичный ввод-вывод означает всего-навсего, чтотакой замены происходить не будет; тем не менее двоичный режим необходим при работе с сырыми данными, т. е. данными в машинной форме без преобразования их в текстовый формат.

Чтобы открыть файл в двоичном режиме, нужно, как уже упоминалось, установить в параметре mode конструктора потока или функции open() бит ios::binary.

Чтение и запись сырых данных

Чтение сырых данных производится функцией read () класса istream:

istream &read(char *buf, long len);

Здесь buf — адрес буфера, в который будут читаться данные, а len — число символов, которые нужно прочитать.

Запись сырых данных производится функцией write () класса ostream. Она выглядит точно так же, как функция read () :

ostream &write(char *buf, long len);

Здесь buf — адрес буфера, в котором содержатся данные, а len — число символов, которые должны быть записаны в поток.

Обе функции возвращают ссылку на свой объект-поток. Это означает, что возможны их цепные вызовы, т. е. выражения вроде

ostream os (...);

os.write(...).write (...).write(...) ;

Вот небольшой пример записи и чтения сырых данных:

#include <iostream.h>

#include <fstream.h>

int main(void) {

char name[] = "testfile.dat";

int i = 1234567;

double d = 2.718281828;

//

// Открытие выходного потока в двоичном режиме

//и запись тестовых данных.

//

ofstream ofs(name, ios::out | ios::binary);

if (ofs) {

ofs.write((char*)&i, sizeof(i)); // Целое.

ofs.write((char*)&d, sizeof(d)); // Вещественное.

ofs.write(name, sizeof(name)); // Строка. ofs.close ();

}

//

// Открытие входного потока в двоичном режиме.

// if stream ifs(name, ios::in | ios::binary) ;

i = 0; //

d = 0; // Уничтожить данные.

name[0] = '\0'; //

//

// Прочитать данные.

//

if (ifs) {

ifs.read((char*)&i, sizeof (i));

ifs.read((char*)&d, sizeof(d));

ifs.read(name, sizeof(name));

ofs.close () ;

} //

// Проверка - напечатать прочитанные данные. //

 
MKPortal©2003-2008 mkportal.it
MultiBoard ©2007-2009 RusMKPortal