Ввод-вывод с произвольным доступом
Под понятием произвольного доступа к файлу подразумевается ряд различных моментов:
- можно произвольно обращаться к любой записи или любому байту в файле, в противоположность последовательному доступу, когда данные извлекаются или передаются в поток строго по очереди;
- в открытом файле можно произвольно чередовать операции чтения и записи;
- ввод-вывод с произвольным доступом является по преимуществу бесформатным.
Для позиционирования потока используются функции 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. Какие виды строк существуют в C++?
2. Как объявить C-строку?
3. Как осуществляется ввод-вывод строк?
4. Какие операции над строками вы знаете?
5. Перечислите операции над символами?
6. Перечислите стандартные потоки ввода-вывода?
7. Как создать файловый поток?
8. Какие режимы открытия файлов существуют?
9. Что такое двоичный режим ввода-вывода?
10. Что такое текстовый режим ввода-вывода?
11. Как осуществляется чтение символов и строк?
12. Как изменить текущую позицию в файле?
13. Как узнать текущую позицию в файле?
14. Для чего используется метод clear()?
Задание
1. Написать программу в соответствии с вариантом задания из пункта 5.
2. Отладить и протестировать программу.
3. Оформить отчёт.
Варианты заданий
Вариант 1
Написать программу, которая считывает из текстового файла три предложения и выводит их в обратном порядке.
Вариант 2
Написать программу, которая считывает текст из файла и выводит на экран только предложения, содержащие введенное с клавиатуры слово.
Вариант 3
Написать программу, которая считывает текст из файла и выводит на экран только строки, содержащие двузначные числа.
Вариант 4
Написать программу, которая считывает английский текст из файла и выводит на экран слова, начинающиеся с гласных букв.
Вариант 5
Написать программу, которая считывает текст из файла и выводит его на экран, меняя местами каждые два соседних слова.
Вариант 6
Написать программу, которая считывает текст из файла и выводит на экран только предложения, не содержащие запятых.
Вариант 7
Написать программу, которая считывает текст из файла и определяет, сколько в нем слов, состоящих не более чем из четырех букв.
Вариант 8
Написать программу, которая считывает текст из файла и выводит на экран только цитаты, то есть предложения, заключенные в кавычки.
Вариант 9
Написать программу, которая считывает текст из файла и выводит на экран только предложения, состоящие из заданного количества слов.
Вариант 10
Написать программу, которая считывает английский текст из файла и выводит на экран слова текста, начинающиеся и оканчивающиеся на гласные буквы.
Вариант 11
Написать программу, которая считывает текст из файла и выводит на экран только строки, не содержащие двузначных чисел.
Вариант 12
Написать программу, которая считывает текст из файла и выводит на экран только предложения, начинающиеся с тире, перед которым могут находиться только пробельные символы.
Вариант 13
Написать программу, которая считывает английский текст из файла и выводит его на экран, заменив каждую первую букву слов, начинающихся с гласной буквы, на прописную.
Вариант 14
Написать программу, которая считывает текст из файла и выводит его на экран, заменив цифры от 0 до 9 на слова «ноль», «один», ..., «девять», начиная каждое предложение с новой строки.
Вариант 15
Написать программу, которая считывает текст из файла, находит самое длинное слово и определяет, сколько раз оно встретилось в тексте.
Вариант 16
Написать программу, которая считывает текст из файла и выводит на экран сначала вопросительные, а затем восклицательные предложения.
Вариант 17
Написать программу, которая считывает текст из файла и выводит его на экран, после каждого предложения добавляя, сколько раз встретилось в нем введенное с клавиатуры слово.
Вариант 18
Написать программу, которая считывает текст из файла и выводит на экран все его предложения в обратном порядке.
Вариант 19
Написать программу, которая считывает текст из файла и выводит на экран сначала предложения, начинающиеся с однобуквенных слов, а затем все остальные.
Вариант 20
Написать программу, которая считывает текст из файла и выводит на экран предложения, содержащие максимальное количество знаков пунктуации.
Вариант 21
Написать программу, которая считывает текст из одного файла, содержащего только цифры. Выводит его содержимое на экран, и записывает в другой файл заменив цифры от 0 до 9 на слова «ноль», «один», ..., «девять», начиная каждое число с новой строки, а цифры разделяя пробелами.
Вариант 22
Написать программу, которая считывает текст из файла и записывает в другой только строки, не содержащие символов пунктуации (точка, запятая и т.д.)
Вариант 23
Написать программу, которая считывает текст из файла и определяет, сколько в нем строчек, содержащих не более чем три пустых символа (пробел, табуляция и.т.д.).
Вариант 24
Написать программу, которая считывает из одного текстового файла строчки и сохраняет их в другой файл в обратном порядке.
Вариант 25
Написать программу, которая считывает текст с экрана в файл и выводит его обратно на экран, заменяя арабские цифры римскими (представление чисел не учитывать, заменять только сами цифры).
Содержание отчета
1. Титульный лист.
2. Наименование и цель работы.
3. Краткое теоретическое описание.
4. Задание на лабораторную работу.
5. Схема алгоритма.
6. Листинг программы.
7. Результаты выполнения программы.