Ввод-вывод с использованием потоковых классов. Произвольный доступ к файлам

   
На этом шаге мы рассмотрим средства произвольного доступа к файлам.

   
В таблице 1 перечислены функции позиционирования в потоках данных C++.

Таблица 1. Функции позиционирования в потоках данных

Класс Функция Описание
basic_istream<> tellg() Возвращает текущую позицию чтения
seekg(pos) Устанавливает абсолютную позицию чтения
seekg(offset, rpos) Устанавливает относительную позицию чтения
basic_ostream<> tellp() Возвращает текущую позицию записи
seekp(pos) Устанавливает абсолютную позицию записи
seekp(offset, rpos) Устанавливает относительную позицию записи

   
Позиционирование чтения и записи выполняется отдельными функциями (суффикс "g" означает "get", а суффикс "р" - "put").
Функции чтения определяются в классе basic_istream, а функции записи - в классе basic_ostream. Тем не менее не все потоковые
классы поддерживают позиционирование. Например, для потоков данных cin, cout и cerr позиционирование не определено. Операции
файлового позиционирования определяются в базовых классах, потому что обычно используются ссылки на объекты типов istream и ostream.

   
Функции seekg() и seekp() могут вызываться для абсолютных или относительных позиций. Функции tellg() и tellp() возвращают
абсолютную позицию в виде значения типа pos_type. Это значение не является целым числом или индексом, задающим позицию символа,
поскольку логическая позиция может отличаться от фактической. Например, в текстовых файлах MS-DOS символы новой строки хранятся в
файлах в виде двух символов, хотя логически они соответствуют только одному символу. Кроме того, ситуация дополнительно усложняется при многобайтовой кодировке символов.

   
Разобраться в точном определении типа pos_type непросто: стандартная библиотека C++ определяет глобальный класс шаблона
fpos<> для представления позиций в файлах. На базе класса fpos<> определяются типы streampos (для потоков
данных char) и wstreampos (для потоков даииых wchar_t). Эти типы используются для определения pos_type соответствующих
классов трактовок. Наконец, переменная типа pos_type класса трактовок требуется для определения типа pos_type соответствующих
потоковых классов. Следовательно, позиции в потоке данных также могут представляться типом streampos, ио использовать типы
long и unsigned long было бы неправильно, потому что streampos не является целочисленным типом (а точнее, перестал им
быть). Пример:

// Сохранение текущей позиции
std::ios::pos_type pos = file.tellg();
// Переход к позиции, хранящейся в pos 
file.seekg(pos);

   
Следующие объявления эквивалентны:

std::ios::pos_type pos; 
std::streampos pos;

   
В версиях с относительным позиционированием смещение задается по отношению к трем позициям, для которых определены соответствующие константы
(таблица 2). Константы определяются в классе ios_base и относятся к типу seekdir.

Таблица 2. Константы относительных позиций

Константа Описание
beg Смещение задается относительно начала файла
cur Смещение задается относительно текущей позиции
end Смещение задается относительно конца файла

   
Смещение относится к типу off_type, который представляет собой косвенное определение для streamoff. По аналогии с pos_type
тип streamoff используется для определения off_type в классе трактовок и в потоковых классах. Тем не менее streamoff
является целым знаковым типом, поэтому смещение в потоке данных может задаваться целым числом. Пример:

// Позиционирование в начало файла 
file.seekg (0, std::ios::beg);
// Позиционирование на 20 символов вперед 
file.seekg (20, std::ios::cur);
// Позиционирование на 10 символов от конца файла 
file.seekg (-10, std::ios::end);

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

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

//---------------------------------------------------------------------------

#include <vcl.h>
// Заголовочные файлы для файлового ввода-вывода
#include <fstream>
#include <iostream>

#include <conio.h>   //необходимо для getch()

#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
using namespace std;

std::string ToRus(const std::string &in)
{
  char *buff = new char [in.length()+1];
  CharToOem(in.c_str(),buff);
  std::string out(buff);
  delete [] buff;
  return out;
}

void printFileTwice (const char* filename)
{
  // Открытие файла
  std::ifstream file(filename);

  // Первый вывод содержимого
  std::cout << file.rdbuf();

  // Возврат к началу файла
  file.seekg(0);

  // Второй вывод содержимого
  std::cout << file.rdbuf();
}


int main (int argc, char* argv[])
{
  // Двукратный вывод всех файлов, переданных в командной строке
  for (int i=1; i<argc; ++i) {
      printFileTwice(argv[i]);
  }
  cout << ToRus("Работа выполнена");

  getch();
  return 0;
}

//---------------------------------------------------------------------------

Текст этого примера можно взять 479 шаг), вам придется
сбросить состояние файла file функцией clear() перед тем, как выполнять с ним любые операции, включая изменение позиции чтения,
поскольку эти функции устанавливают флаги ios::eofbit и ios::failbit при достижении конца файла.

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

   
На следующем шаге мы рассмотрим файловые дескрипторы.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий