Программирование на C и C++

Онлайн справочник программиста на C и C++

Двоичный ввод/вывод

Имеется несколько способов для записи двоичных данных в файл и чтения из файла. В этом разделе мы рассмотрим два из них. В первую очередь, можно записать байт с помощью функции-члена put() и прочитать байт, используя функцию-член get(). Функция get() имеет много форм, но наи­более употребительна показанная ниже версия, где приведена также функция put():

istream &get(char &ch);

ostream &put(char ch);

Функция get() читает единственный символ из ассоциированного потока и помещает его значе­ние в ch. Она возвращает ссылку на поток. Функция put() пишет ch в поток и возвращает ссылку на этот поток.

ЗАМЕТКА: Работая с двоичными файлами, надо удостовериться, что они от­крыты с использованием спецификатора ios::binary.

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

#include <iostream.h>
#include <fstream.h>
int main(int argc, char *argv[])
{
char ch;
if (argc!=2) {
cout << "Usage: PR <filename>\n";
return 1;
}
ifstream in(argv[1], ios::in | ios::binary);
if (!in) {
cout << "Cannot open file.\n";
return 1;
}
while (in) { // in будет нулем при достижении конца файла
in.get (ch);
cout << ch;
}
in.close();
return 0;
}

Когда in достигает конца файла, то принимает значение NULL, в результате чего цикл while заканчивается.

Имеется более компактная запись кода для этого цикла, как показано ниже:

while (in.get(ch))
cout << ch;

Такая запись работает, поскольку функция get() возвращает поток in, обращающийся в нуль, когда достигается конец файла.

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

#include <iostream.h>
#include <fstream.h>
int main()
{
char *p = "hello there\n\r\xfe\xff";
ofstream out("test", ios::out | ios::binary );
if (!out) {
cout << "Cannot open file.\n";
return 1;
}
while (*p) out.put (*p++);
out.close ();
return 0;
}

Второй способ чтения и записи двоичных данных состоит в использовании функций read() и write(). Наиболее обычный способ использования этих функций соответствует прототипу:

istream &read(unsigned char *buf, int num);

ostream &write(const unsigned char *buf, int num);


Функция read() читает num байт из ассоциированного потока и посылает их в буфер buf. Фун­кция write() пишет num байт в ассоциированный поток из буфера buf.

Следующая программа пишет и потом читает массив целых чисел:

#include <iostream.h>
#include <fstream.h>
int main()
{
int n [5] = {1, 2, 3, 4, 5};
register int i;
ofstream out ("test", ios::out | ios::binary);
if (!out) {
cout << "Cannot open file.\n";
return 1;
}
out.write((unsigned char *) &n, sizeof n);
out.close();
for (i=0; i<5; i++) // очистка массива
n[i] = 0;
ifstream in ("test", ios::in | ios::binary);
in.read((unsigned char *) &n, sizeof n);
for (i=0; i<5; i++) // вывести значения, прочитанные из файла
cout << n[i] << " ";
in.сlоse();
return 0;
}

Следует обратить внимание, что приведение типов в вызовах read() и write() необходимо для работы с буфером, который не определен как массив символов.

Если конец файла достигается до того, как будет прочитано заданное число символов, функ­ция read() просто прекращает работу и буфер содержит столько символов, сколько было прочи­тано. Можно определить, сколько символов было прочитано, используя другую функцию-член gcount(), имеющую следующий прототип:

int gcount();

Она возвращает число символов, прочитанных последним оператором двоичного ввода.