Под понятием произвольного доступа к файлу подразумевается ряд различных моментов:
· можно произвольно обращаться к любой записи или любому байту в файле, в противоположность последовательному доступу, когда данные извлекаются или передаются в поток строго по очереди;
· в открытом файле можно произвольно чередовать операции чтения и записи;
· ввод-вывод с произвольным доступом является по преимуществу бесформатным.
Для позиционирования потока используются функции seekg() и seekp().
Разница между ними в том, что первая перемещает позицию чтения в потоке, а вторая устанавливает новую позицию в выходном потоке. Если используется поток типа fstream, и он открыт в режиме чтения-записи, то все равно, какую функцию применять для позиционирования.
Для определения текущей позиции tellg() и tellp(). Первая возвращает позицию чтения во входном потоке, а вторая – позицию в выходном потоке.
Примеры программ
Рассмотрим примеры использования функции работы с файлами и строками.
Пример 11.3 Поиск вхождения слова в файле
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main ()
{
setlocale ( LC_ALL, "Russian" );
const int len = 81;
char word [ len ], line [ len ], end_word [] = "done";
//пересоздадим файл и откроем для чтения/записи
fstream f ( "lab11.txt", ios :: in | ios :: out | ios :: trunc );
if (! f )
{
cout << "Ошибка открытия файла" << endl;
return - 1;
}
//введем несколько строк для дальнейшего поиска в них
do
{
cin >> line;
//с файловым потоком можно работать как со стандартными cin и cout
f << line << endl;
}
//продолжаем пока не введем done
while ( strcmp ( line, end_word ));
//сбросим файловый поток на начало
f. seekg ( 0 );
cout << "Содержимое файла: " << endl;
//содержимое файла на экран
//выполняем пока не достигнем конца файла
while (! f. eof ())
{
f >> line;
cout << line << endl;
}
cout << "Введите слово для поиска: ";
cin >> word;
//сбрасываем бит-признак конца файла eofbit
f. clear ();
//сбросим файловый поток на начало
f. seekg ( 0 );
//определим длину искомого слова
size_t l_word = strlen ( word );
//счетчик вхождения слова
int wc = 0;
//читаем построчно и ищем слово word в строке
while ( f. getline ( line, len ))
{
//поместим указатель p на начало строки
char * p = line;
//strstr возвращает указатель
// на элемент из строки p с которого начинается word
while ( p = strstr ( p, word ))
{
//используем указатель не текущую позицию в строке
char * c = p;
//переместим p на символ сразу за концом слова
p += l_word;
//проверим стоит ли наше слово отдельно
//или это просто подстрока в другом (большем) слове
//проверим совпадает ли начало слова с началом строки
if ( c != line )
//проверим символ перед началом слова
//на принадлежность к разделителям
if (! ispunct (*( c - 1 )) &&! isspace (*( c - 1 )))
//начинается не с начала строки и
//не с разделителя => ищем дальше
continue;
//символы перед началом слова подходят
//проверяем символы за окончанием слова
//если это пробелы, символы пунктуации
//или конец строки => увеличиваем счетчик слов
if ( ispunct (* p ) || isspace (* p ) || (* p == '\0' ))
{
wc ++;
cout << "Слово найдено" << endl;
}
}
}
cout << "Количество вхождений слова: " << wc << endl;
return 0;
}
Рассмотрим другой подход к решению предложенной выше задачи. В библиотеке C++ есть функция strtok, которая разбивает предложенную строку на лексемы в соответствии с заданным набором разделителей. При ее использовании нет необходимости выделять и проверять начало и конец слова. Потребуется лишь сравнит с искомым словом, слово, выделенное strtok. Для этого просто необходимо задать разделители.
Пример 11.4 Поиск вхождения слова в файле с помощью strtok
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main ()
{
setlocale ( LC_ALL, "Russian" );
const int len = 81;
char word [ len ], line [ len ], end_word [] = "done";
//пересоздадим файл и откроем для чтения/записи
fstream f ( "lab11.txt", ios :: in | ios :: out | ios :: trunc );
if (! f )
{
cout << "Ошибка открытия файла" << endl;
return - 1;
}
//введем несколько строк для дальнейшего поиска в них
do
{
cin >> line;
f << line << endl;
}
//продолжаемпоканевведем done
while ( strcmp ( line, end_word ));
cout << "Введите слово для поиска: ";
cin >> word;
//сбрасываем бит-признак конца файла eofbit
f. clear ();
//сбросим файловый поток на начало
f. seekg ( 0 );
//Список разделителей
char delims [] = ",.!? /<>|()*:;\"";
//Указатель на начало слова
char * token;
//счетчик вхождения слова
int wc = 0;
//читаем построчно и ищем слово word в строке
while ( f. getline ( line, len ))
{
//находим первый символ не из разделителей
//находим первый символ не из разделителей
token = strtok ( line, delims );
//проверяем, остались ли еще слова
while ( token != NULL )
{
//strtok заменяет символ после разделителя
//на NULL поэтому можно сравнивать искомое и
//найденноеслово
if (! strcmp ( token, word ))
wc ++;
//Для поиска следующей лексемы в той же строке
//strtok необходимо передать NULL
token = strtok ( NULL, delims );
}
}
cout << "Количество вхождений слова: " << wc << endl;
return 0;
}
Пример 11.5 Произвольный доступ к файлу
// Открыть файл как двоичный сразу для ввода и вывода
// (создать новый, если отсутствует или перезаписать старый)
// Ввести элементы с клавиатуры
// Поменять знак четных элементов
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
int main ()
{
setlocale ( LC_ALL, "Russian" );
const int NP = 10;
const int IS = sizeof(int); //размерэлемента int
int pt, i;
// Открытие файла для чтения/записи.
fstream fs ( "random.txt",
ios :: binary | ios :: in | ios :: out | ios :: trunc );
if (! fs )
{ cerr << "Ошибка открытия файла." << endl;
return 1; }
// Первоначальная запись файла.
cout << "Начальныезаняения:" << endl;
for ( i = 0; i < NP; i ++)
{ pt = i;
//Приводим pt к типу char* для нормальной работы write
fs. write ((char*)& pt, IS );
cout << setw ( 4 ) << pt; }
cout << endl << endl;
// Чтение файла от конца к началу.
cout << "Читаем из файла в обратном порядке:" << endl;
for ( i = 0; i < NP; i ++)
{
//Перемещаемся к i-му элементу с конца
fs. seekg (-( i + 1 ) * IS, ios :: end );
//Приводим pt к типу char* для нормальной работы read
fs. read ((char*)& pt, IS );
cout << setw ( 4 )<< pt;
};
cout << endl << endl;
// Переписать четные индексы.
for ( i = 1; i < NP / 2; i ++)
{
//перемещаемся к i-му элементу
fs. seekg ( 2 * i * IS );
//читаем i-ыйэлемент
fs. read ((char*)& pt, IS );
//меняем значение на противоположное
pt = - pt;
//возвращаемся на шаг назад, к только что прочитанному элементу
int p = fs. tellg ();
p -= IS;
fs. seekg ( p );
//перезаписываемего
fs. write ((char*)& pt, IS ); }
//выводим файл на экран
cout << "После перезаписи:" << endl;
fs. seekg ( 0 );
for ( i = 0; i < NP; i ++)
{ fs. read ((char*)& pt, IS );
cout << setw ( 4 ) << pt; }
cout << endl;
fs. close ();
return 0 ;}
Замечание. Когда эта программа открывает уже существующий файл, он усекается до нулевой длины (т.е. все его данные теряются). Если необходимо работать с уже имеющимися в файле данными, нужно убрать бит ios::trunc из режима открытия потока.
Варианты заданий
Вариант 1
Написать программу, которая считывает текст из файла и выводит на экран только цитаты, то есть предложения, заключенные в кавычки.
Вариант 2
Написать программу, которая считывает текст из файла и выводит на экран только предложения, состоящие из заданного количества слов.
Вариант 3
Написать программу, которая считывает английский текст из файла и выводит на экран слова текста, начинающиеся и оканчивающиеся на гласные буквы.
Вариант 4
Написать программу, которая считывает текст из файла и выводит на экран только строки, не содержащие двузначных чисел.
Вариант 5
Написать программу, которая считывает текст из файла и выводит на экран только предложения, начинающиеся с тире, перед которым могут находиться только пробельные символы.
Вариант 6
Написать программу, которая считывает английский текст из файла и выводит его на экран, заменив каждую первую букву слов, начинающихся с гласной буквы, на прописную.
Вариант 7
Написать программу, которая считывает текст из файла и выводит его на экран, заменив цифры от 0 до 9 на слова «ноль», «один»,..., «девять», начиная каждое предложение с новой строки.
Вариант 8
Написать программу, которая считывает текст из файла, находит самое длинное слово и определяет, сколько раз оно встретилось в тексте.
Вариант 9
Написать программу, которая считывает текст из файла и выводит на экран сначала вопросительные, а затем восклицательные предложения.
Вариант 10
Написать программу, которая считывает текст из файла и выводит его на экран, после каждого предложения добавляя, сколько раз встретилось в нем введенное с клавиатуры слово.
Вариант 11
Написать программу, которая считывает текст из файла и выводит на экран все его предложения в обратном порядке.
Вариант 12
Написать программу, которая считывает текст из файла и выводит на экран сначала предложения, начинающиеся с однобуквенных слов, а затем все остальные.
Вариант 13
Написать программу, которая считывает текст из файла и выводит на экран предложения, содержащие максимальное количество знаков пунктуации.
Вариант 14
Написать программу, которая считывает текст из одного файла, содержащего только цифры. Выводит его содержимое на экран, и записывает в другой файл заменив цифры от 0 до 9 на слова «ноль», «один»,..., «девять», начиная каждое число с новой строки, а цифры разделяя пробелами.