// операция ios_base::out стерла бы текущие данные
file.open( "word.out", ios::app );
file endl wd endl;
file.close();
}
Объект класса fstream может также открывать файл одновременно для ввода и вывода. Например, приведенная инструкция открывает файл word.out для ввода и дозаписи:
fstream io( "word.out", ios_base::in|ios_base::app );
Для задания нескольких режимов используется оператор побитового ИЛИ. Объект класса fstream можно позиционировать с помощью функций-членов seekg() или seekp(). Здесь буква g обозначает позиционирование для чтения (getting) символов (используется с объектом класса ofstream), а p – для записи (putting) символов (используется с объектом класса ifstream). Эти функции делают текущим тот байт в файле, который имеет указанное абсолютное или относительное смещение. У них есть два варианта:
// установить абсолютное смещение в файле
seekg( pos_type current_position )
// смещение от текущей позиции в том или ином направлении
seekg( off_type offset_position, ios_base::seekdir dir );
В первом варианте текущая позиция устанавливается в некоторое абсолютное значение, заданное аргументом current_position, причем значение 0 соответствует началу файла. Например, если файл содержит такую последовательность символов:
abc def ghi jkl
то вызов
io.seekg( 6 );
* позиционирует io на шестой символ, т.е. на f. Второй вариант устанавливает указатель рабочей позиции файла на заданное расстояние от текущей, от начала файла или от его конца в зависимости от аргумента dir, который может принимать следующие значения: ios_base::beg – от начала файла;
* ios_base::cur – от текущей позиции;
* ios_base::end – от конца файла.
В следующем примере каждый вызов seekg() позиционирует файл на i-ую запись:
for ( int i = 0; i recordCnt; ++i )
readFile.ssekg( i * sizeof(Record), ios_base::beg );
С помощью первого аргумента можно задавать отрицательное значение. Переместимся на 10 байтов назад от текущей позиции:
readFile.seekg( -10, ios_base::cur );
Текущая позиция чтения в файле типа fstream возвращается любой из двух функций-членов tellg() или tellp(). Здесь 'p' означает запись (putting) и используется с объектом ofstream, а 'g' говорит о чтении (getting) и обслуживает объект ifstream:
// сохранить текущую позицию
ios_base::pos_type mark = writeFile.tellp();
// ...
if ( cancelEntry )
// вернуться к сохраненной позиции
writeFile.seekp( mark );
Если необходимо сместиться вперед от текущей позиции на одну запись типа Record, то можно воспользоваться любой из данных инструкций:
// эквивалентные вызовы seekg
readFile.seekg( readFile.tellg() + sizeof(Record) );
// данный вызов считается более эффективным
readFile.seekg( sizeof(Record), ios_base::cur );
Разберем реальный пример. Дан текстовый файл, нужно вычислить его длину в байтах и сохранить ее в конце файла. Кроме того, каждый раз при встрече символа новой строки требуется сохранить текущее смещение в конце файла. Вот наш текстовый файл:
abcd
efg
hi
j
Программа должна создать файл, модифицированный следующим образом:
abcd
efg
hi
j
5 9 12 14 24
Так выглядит первая попытка реализации:
#include iostream
#include fstream
main() {
// открыть файл для ввода и дозаписи
fstream inOut( "copy.out", ios_base::in|ios_base::app );
int cnt = 0; // счетчик байтов
char ch;
while ( inOut.get( ch ))
{
cout.put( ch ); // скопировать на терминал
++cnt;
if ( ch == '\n' ) {
inOut cnt ;
inOut.put( ' ' ); // пробел
}
}
// вывести окончательное значение счетчика байтов
inOut cnt endl;
cout "[ " cnt " ]" endl;
return 0;
}
inOut – это объект класса fstream, связанный с файлом copy.out, открытым для ввода и дозаписи. Если файл открыт в режиме дозаписи, то все новые данные записываются в конец.