Читаем Программирование полностью

Разница между хранением двоичного представления фиксированного размера (например, в виде типа int) и символьного представления переменного размера (например, в виде типа string) проявляется и при работе с файлами. По умолчанию потоки iostream работают с символьными представлениями; иначе говоря, поток istream считывает последовательность символов и превращает их в объект заданного типа. Поток ostream принимает объект заданного типа и преобразует их в последовательность записываемых символов. Однако можно потребовать, чтобы потоки istream и ostream просто копировали байты из файла в файл. Такой ввод-вывод называется двоичным (binary I/O). В этом случае файл необходимо открыть в режиме ios_base::binary. Рассмотрим пример, в котором считываются и записываются двоичные файлы, содержащие целые числа. Главные сроки, предназначенные для обработки двоичных файлов, объясняются ниже.

int main()

{

  // открываем поток istream для двоичного ввода из файла:

  cout << "Пожалуйста, введите имя файла для ввода \n";

  string name;

  cin >> name;

  ifstream ifs(name.c_str(),ios_base::binary); // примечание: опция

      // binary сообщает потоку, чтобы он ничего не делал

      // с байтами

  if (!ifs) error("Невозможно открыть файл для ввода ", name);

      // открываем поток ostream для двоичного вывода в файл:

  cout << "Пожалуйста, введите имя файла для вывода \n";

  cin >> name;

  ofstream ofs(name.c_str(),ios_base::binary); // примечание: опция

      // binary сообщает потоку, чтобы он ничего не делал

      // с байтами

  if (!ofs) error("Невозможно открыть файл для ввода ",name);

  vector v;

      // чтение из бинарного файла:

  int i;

  while (ifs.read(as_bytes(i),sizeof(int))) // примечание:

                                            // читаем байты

      v.push_back(i);

      // ...что-то делаем с вектором v...

      // записываем в двоичный файл:

  for(int i=0; i

    ofs.write(as_bytes(v[i]),sizeof(int)); // примечание:

                                           // запись байтов

  return 0;

}

Мы открыли эти файлы с помощью опции ios_base::binary.

ifstream ifs(name.c_str(), ios_base::binary);

ofstream ofs(name.c_str(), ios_base::binary);

В обоих вариантах мы выбрали более сложное, но часто более компактное двоичное представление. Если мы перейдем от символьно-ориентированного ввода-вывода к двоичному, то не сможем использовать обычные операторы ввода и вывода >> и <<. Эти операторы преобразуют значения в последовательности символов, руководствуясь установленными по умолчанию правилами (например, строка "asdf" превращается в символы a, s, d, f, а число 123 превращается в символы 1, 2, 3). Если вы не хотите работать с двоичным представлением чисел, достаточно ничего не делать и использовать режим, заданный по умолчанию. Мы рекомендуем применять опцию binary, только если вы (или кто-нибудь еще) считаете, что так будет лучше. Например, с помощью опции binary можно сообщить потоку, что он ничего не должен делать с байтами.

А что вообще мы могли бы сделать с типом int? Очевидно, записать его в память размером четыре байта; иначе говоря, мы могли бы обратиться к представлению типа int в памяти (последовательность четырех байтов) и записать эти байты в файл. Позднее мы могли бы преобразовать эти байты обратно в целое число.

ifs.read(as_bytes(i),sizeof(int))     // чтение байтов

ofs.write(as_bytes(v[i]),sizeof(int)) // запись байтов

Функция write() потока ostream и функция read() потока istream принимают адрес (с помощью функции as_bytes()) и количество байтов (символов), полученное с помощью оператора sizeof. Этот адрес должен ссылаться на первый байт в памяти, хранящей значение, которое мы хотим прочитать или записать. Например, если у нас есть объект типа int со значением 1234, то мы могли бы получить четыре байта (используя шестнадцатеричную систему обозначений) — 00, 00, 04, d2:

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже