Операций извлечения/передачи данных перегружены для всех встроенных типов и выполняют соответствующие преобразования из внутреннего представления данных в текстовое и из текстового во внутреннее (машинное). Однако в библиотеке 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(...);
Чтение символов и строк
Для чтения одиночных символов, а также строк применяется функция get класса istream. Эта функция перегружена следующим образом:
int get();
istream &get(char &c);
istream &get(char *buf, long len, char t = '\n');
Две первые формы функции предназначены для извлечения из потока одиночного символа. Функция int get() возвращает символ в качестве своего значения. Функция get (char &c) передает символ в параметре и возвращает ссылку на свой поток.
Пример 11.1 Блок посимвольного копирования файлов
ifstream ifs("infile.dat");
ofstream ofs("outfile.dat");
// put (char) передает в поток
// одиночный символ.
while (ifs & ofs)
ofs.put(ifs.get());
Последняя форма функции get() извлекает из потока последовательность символов. Символы читаются в буфер buf, пока не произойдет одно из следующих событий:
- будет встречен ограничивающий символ t (по умолчанию '\n');
- будет встречен конец файла;
- в буфер будет записано len символов, включая завершающий строку 0.
Имеется еще функция getline(), во всем аналогичная этой форме get():
istream &getline(char *buf, long len, char t = '\n');
Разница между этими двумя функциями состоит в том, что getline() извлекает из потока ограничивающий символ, в то время как get() этого не делает. Ни та, ни другая функция не записывает ограничивающий символ в буфер.
Пример 11.2 Блок чтения строк с помощью get()
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
setlocale(LC_ALL, "Russian");
char name[9], ext[4];
cout << "Введите имя файла: ";
cin.get(name, 9, '.');
cin.ignore (80, '.'); // Удалить все оставшиеся до точки символы
cin.get(ext, 4);
cin.ignore(80, '\n'); // Удалить все, что осталось в строке
cout<< "Имя: "<< name << " Расширение: " << ext << endl;
return 0;
}