Структуры и алгоритмы компьютерной обработки данных

Решение задач на обработку файлов

Разбить на страницы
Показывать лекцию целиком

Цель лекции: изучить использование алгоритмов обработки элементов файла в решении задач и научится приемам решения задач на обработку элементов файла на языке C++.

Потоки для работы с файлами создаются как объекты следующих классов:

ofstream – для вывода (записи) данных в файл;

ifstream – для ввода (чтения) данных из файла;

fstream – для чтения и для записи данных (двунаправленный обмен).

Чтобы использовать эти классы, в текст программы необходимо включить дополнительный заголовочный файл fstream.h. После этого в программе можно определять конкретные файловые потоки, соответствующих типов.

Создание файлового потока (объекта соответствующего класса) связывает имя потока с выделяемым для него буфером и инициализирует переменные состояния потока. Так как перечисленные классы файловых потоков наследуют свойства класса ios, то и переменные состояния каждого файлового потока наследуются из этого базового класса. Файловые классы являются производными от классов ostream (класс ofstream ), istream (класс ifstream ), stream (класс fstream ), они поддерживают описанный в предыдущих шагах форматированный и бесформатный обмен с файлами. Однако прежде чем выполнить обмен, необходимо открыть соответствующий файл и связать его с файловым потоком.

Открытие файла в самом общем смысле означает процедуру, информирующую систему о тех действиях, которые предполагается выполнять с файлом. Работая с файловыми потоками с помощью библиотек ввода-вывода языка С++, удобнее пользоваться компонентными функциями соответствующих классов.

Большинство средств управления потоковым вводом-выводом сосредоточены в классе ios, который является базовым для ostream и istream. По сути здесь находится управление связью между istream или ostream и буфером, используемым для операций ввода-вывода. Именно класс ios контролирует работу буфера обмена: как символы заносятся и как они считываются.

Класс ios (iostream.h)

Обеспечивает общие операции для ввода и вывода. Производные от него классы ( istream, ostream, iostream ) специализируют ввод-вывод с помощью операций форматирования высокого уровня. Класс ios является базовым для istream, ostream, fstreambase и strstreambase.

Флаги форматирования – двоичные коды, управляющие форматом выводимых значений. В заголовочном файле iostream.h определено следующее перечисление, задающее флаги форматирования.

Значения флагов форматирования файла iostream.h
skipws 0х0001 Пропускает при вводе пробелы и разделители.
left 0х0002 Выравнивание вывода влево.
right 0х0004 Выравнивание вывода вправо.
internal 0х0008 Дополнение после знака или указателя основания.
dec 0х0010 Десятичное преобразование.
oct 0х0020 Восьмеричное преобразование.
hex 0х0040 Шестнадцатеричное преобразование.
showbase 0х0080 Показывает в выводе индикатор основания.
showpoint 0х0100 Показывает при выводе с плавающей точкой десятичную точку.
uppercase 0х0200 Преобразует шестнадцатеричный вывод в верхний регистр.
showpos 0х0400 Выводит с положительными числами символ '+'.
scientific 0х0800 Добавляет к числам с плавающей точкой суффикс с показателем степени (E).
fixed 0х1000 Для вывода чисел с плавающей точкой использует десятичную фиксированную точку.
unitbuf 0х2000 После включения выводит все потоки.
stdio 0х4000 После включения выводит stdout и stderr.

Фактически в этом списке содержатся имена констант, определяющие флаги соответствующих назначений. Коду формата соответствует целый тип long. Изменить состояние флагов формата можно с помощью функции класса ios, имеющей прототип

long setf(long flags);

Например, чтобы установить флаг showbase в активный режим (включить) применительно к стандартному потоку вывода cout, используется оператор

cout.setf(ios::showbase);

Для установки флагов можно использовать побитовые операции. Например:

cout.setf(ios::left|ios::hex);

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

Функции класса ios
Функция Прототип Описание
bad int bad(); Ненулевое значение в случае ошибки.
bitalloc static long bitalloc(); Получает новый флаг битового набора. Возвращаемое значение может использовать для установки, очистки и проверки флаги. Это флаги форматирования, определяемые пользователем.
eof int eof(); В случае достижения конца файла возвращает ненулевое значение.
fail int fail(); Не 0 при неуспешном выполнении операции с потоком.
fill char fill(); Возвращает текущий символ-заполнитель потока.
char fill(char); Заменяет значением параметра символ заполнения потока; возвращает ранее установленное значение символа заполнения.
flags long flags(); Возвращает текущее значение флагов форматирования.
long flags(long); Устанавливает флаги форматирования по значению параметра; возвращает ранее установленное значение флагов.
good int good(); Возвращает ненулевое значение, если не установлен ни один флаг (ошибок нет).
presicion int presicion(); Возвращает текущую точность числа с плавающей точкой.
int presicion(int); Устанавливает точность вещественных чисел с плавающее точкой по значению параметра; Возвращает предыдущее значение параметра.
rdbuf streambuf* rdbuf(); Возвращает указатель на streambuf, назначенный для данного потока.
rdstate int rdstate(); Возвращает текущее состояние потока.
setf long setf(long); Устанавливает флаги по значению параметра; возвращает ранее установленные флаги.
sync_with_stdio sync_with_stdio; Смешивает файлы stdio и потоки iostreams. В новой программе этого использовать не следует.
unseft long unseft(long); Очищает биты состояния потока, отмеченные параметром; возвращает предыдущее состояние битов.
with int with(); Возвращает текущее значение ширины.
int with(int); Устанавливает ширину, равную параметру; возвращает предыдущее значение параметра.
gcount int gcount(); Возвращает число символов, извлеченных из потока последним обращением.
get int get(); Получает следующий символ либо EOF, сохраняя их в буфере.
int get(signed char*, int, char='\n'); Извлекает из входного потока символы и помещает их в буфер, на начало которого указывает char*. Передача завершается, если число принятых символов на 1 меньше второго параметра или встретился символ '\n'.
getline iostream getline(signed char*, int, char='\n'); Извлекает из входного потока символы и помещает их в буфер, на начало которого указывает char*. Передача завершается, если число принятых символов на 1 меньше второго параметра или встретился символ '\n',который помещается в строку.
ignore iostream ignore(int n, int delim); Пропускает n символов в потоке. При обнаружении delim останавливается (по умолчанию, delim=EOF ).
peek int peek(); Возвращает следующий символ без извлечения из потока.
putback iostream putback(char); Помещает символ обратно в поток.
read read(signed char*, int); Извлекает из потока и помещает в символьный массив указанное число символов.
seekg iostream seekg(long); Перемещает заданное число байт относительно текущей позиции для потока ввода. Можно задавать направление.
telig Long telig(); Возвращает текущую позицию курсора. В случае неуспешного выполнения возвращает отрицательное число.
flush ostream flush(); Флэширует внутренний буфер выходного потока.
put ostream put(char); Помещает заданный параметром char символ в выходной поток.
seekp ostream seekp (long); Устанавливает указатель записи выходного потока на абсолютную позицию, заданную параметром long.
ostream seekp (long, seek_dir); Перемещает указатель текущей позиции выходного потока на число байтов, заданное первым параметром. Второй параметр задает точку отсчета (0 – начало; 1 – текущая позиция; 2 – конец потока)
tellp long tellp(); Возвращает текущую позицию выходного потока.
write ostream write (const signed, char *, int n); Помещает в выходной поток n символов из массива, на который указывает char *. Нуль-символы включаются в число переносимых символов.
ostream write (const signed, char *, int n);

Пример 1. Входной файл содержит следующую информацию: в первой строке натуральное число указывает количество чисел, далее следуют вещественные числа. Выведите в выходной файл только положительные числа из входного файла и их сумму.

#include "stdafx.h"
#include <iostream>
using namespace std;
#include <fstream> 
int _tmain(int argc, _TCHAR* argv[]){
  int n,i=1; 
  float s, sum=0.0;
  // Открываем входной файл для ввода данных
  ifstream infile("in.txt"); 
  // Открываем выходной файл для вывода данных
  ofstream outfile("out.txt"); 
  // Проверка корректности открытия входного файла
  if (!infile) {cout << "Файл не открыт.\n";} 
    else {
      infile >> n; //Считываем количество чисел
      while (i++<=n){
        infile >> s; //Считываем вещественные числа
        if (s>0) {
            sum+=s;
            outfile << s <<"\n"; 
            //Выводим положительные числа  
                 }
        }
        outfile << sum; //Выводим сумму в выходной файл
        // Закрываем файлы 
        infile.close();
        outfile.close(); 
        cout << "Запись в файл завершена"; 
      }
  system("pause");
  return 0;
}

Пример 2. Дан текстовый файл. Выведите в выходной файл длину наибольшей строки и все строки такой длины.

#include "stdafx.h"
#include <iostream>
using namespace std;
#include <fstream> 
#include <string.h>
int _tmain(int argc, _TCHAR* argv[]){
  int maxlen=0, len; 
  char st[200],delim;
  //Связываем переменные с потоками
  ifstream infile; 
  ofstream outfile;
  // Открываем входной файл для ввода данных
  infile.open("in.txt"); 
  // Проверка корректности открытия входного файла
  if (!infile) {cout << "Файл не открыт.\n";} 
  else {
    //Поиск максимальной длины строк       
    while (!infile.eof()) {
      infile.getline(st,200,delim='\n');
      len=strlen(st); 
      if (len>maxlen) maxlen=len;
    }
    // Закрываем входной файл 
    infile.close();
  }
   //Открываем входной файл для ввода данных
   infile.open("in.txt"); 
   // Открываем выходной файл для вывода данных
   outfile.open("out.txt");
  // Проверка корректности открытия входного файла
  if (!infile) {cout << "Файл не открыт.\n";} 
  else {
    outfile<<"Длина наибольшей строки равна "<<maxlen<<"\n";
    //Поиск и вывод строк максимальной длины
    while (!infile.eof()) {
      infile.getline(st,200,delim='\n');
      len=strlen(st);
      if (len==maxlen) outfile <<st<<"\n";
    }
    // Закрываем файлы 
    infile.close(); 
    outfile.close(); 
    cout << "Запись в файл завершена";
  }  
  system("pause");
  return 0;
}

Ключевые термины

Извлечение из потока – это процесс чтения данных из потока.

Класс fstream – это поток для чтения и для записи данных (двунаправленный обмен).

Класс ifstream – это поток для ввода (чтения) данных из файла

Класс iosродительский класс для файловых потоков.

Класс ofstream – это поток для вывода (записи) данных в файл.

Помещение или включение в поток – это процесс вывода данных в поток.

Поток – это абстрактное понятие, относящееся к любому переносу данных от источника к приемнику.

Флаги форматирования – двоичные коды, управляющие форматом выводимых значений.

Краткие итоги

  • Файловые потоки ofstream, ifstream, fstream наследуются из базового класса ios.
  • Класс ios контролирует работу буфера обмена.
  • Создание файлового потока связывает имя потока с выделяемым для него буфером и инициализирует переменные состояния потока.
  • Флаги форматирования управляют форматом выводимых значений.
  • Файловые потоки используются для обмена данными при решении задач.
  • Лабораторная работа 23. Решение задач на обработку файлов

    Цель работы: изучить использование алгоритмов обработки элементов файла в решении задач и научится приемам решения задач на обработку элементов файла на языке C++.

    При выполнении лабораторной работы для каждого задания требуется написать программу на языке С++, которая получает на входе строковые величины, являющиеся корректными именами входных и выходных файлов (при этом в программе следует предусмотреть проверку существования и корректности открытия используемых файлов). Ввод данных осуществляется из входных файлов с учетом требований к входным данным, содержащихся в постановке задачи. Ограничениями на входные данные является максимальный размер строковых данных и допустимый диапазон числовых типов в языке С++. При некорректном открытии файла программа должна завершить работу с выдачей на экран соответствующего сообщения. Считанные из файла данные обрабатываются в соответствии с условием задачи с помощью алгоритмов обработки данных файлов, после чего осуществляется вывод в выходной файл.

    Теоретические сведения.

    Ознакомьтесь с материалом лекции 23.

    Задания к лабораторной работе.

    Выполните приведенные ниже задания.

  • Заполните файл in.dat числами по закономерности: 1/2, 1/4, 2/6, 3/8, 5/16,… Считывая данные из in.dat, заполните файл out.dat квадратами чисел, попавших в отрезок [a, b].
  • Дан входной текстовый файл. Заполните выходной файл только теми строками, в которых ровно k символов ch.
  • Даны два входных текстовых файла. Сформируйте выходной файл из строк, полученных конкатенацией соответствующих по порядку строк входных файлов. Если один из входных файлов закончится раньше, то оставшиеся строки второго файла допишите без изменения.
  • Решите задачу на обработку файла. Использование дополнительного массива не предусматривается. Записать в файл N вещественных чисел. Найти наибольшее из значений модулей компонентов с нечетными номерами. Выведите результат на экран и в файл.
  • Указания к выполнению работы.

    Каждое задание необходимо решить в соответствии с изученными методами и алгоритмами обработки файлов в языке С++. В программном коде к каждой задаче следует выполнять чтение данных из существующих входных файлов (имя каждого файла вводится в виде строки символов и считается корректным с точки зрения организации файловой системы). Данные входных файлов необходимо обработать, применив алгоритмы обработки файлов. В задаче 4 нельзя использовать дополнительные массивы для хранения промежуточных данных. Вывод следует осуществить в выходной файл, имя которого вводится как строка символов с клавиатуры. Данные входного и выходного файлов необходимо дублировать на экране с соответствующими комментариями. Программу для решения каждого задания необходимо разработать методом процедурной абстракции, оформив комментарии к коду.

    Следует реализовать каждое задание в соответствии с приведенными этапами:

  • изучить словесную постановку задачи, выделив при этом все виды данных;
  • сформулировать математическую постановку задачи;
  • выбрать метод решения задачи, если это необходимо;
  • разработать графическую схему алгоритма;
  • записать разработанный алгоритм на языке С++;
  • разработать контрольный тест к программе;
  • отладить программу;
  • представить отчет по работе.
  • Требования к отчету.

    Отчет по лабораторной работе должен соответствовать следующей структуре.

  • Титульный лист.
  • Словесная постановка задачи. В этом подразделе проводится полное описание задачи. Описывается суть задачи, анализ входящих в нее физических величин, область их допустимых значений, единицы их измерения, возможные ограничения, анализ условий при которых задача имеет решение (не имеет решения), анализ ожидаемых результатов.
  • Математическая модель. В этом подразделе вводятся математические описания физических величин и математическое описание их взаимодействий. Цель подраздела – представить решаемую задачу в математической формулировке.
  • Алгоритм решения задачи. В подразделе описывается разработка структуры алгоритма, обосновывается абстракция данных, задача разбивается на подзадачи. Схема алгоритма выполняется по ЕСПД (ГОСТ 19.003-80 и ГОСТ 19.002-80).
  • Листинг программы. Подраздел должен содержать текст программы на языке программирования С++, реализованный в среде MS Visual Studio 2010.
  • Контрольный тест. Подраздел содержит наборы исходных данных и полученные в ходе выполнения программы результаты.
  • Выводы по лабораторной работе.
  • Ответы на контрольные вопросы.
  • Контрольные вопросы

  • Предусмотрены ли флаги форматирования для вводимых в файл значений? Почему?
  • С какой целью выделены как отдельные потоки ofstream, ifstream, fstream?
  • В чем отличие выполнения функции get без параметров и с тремя параметрами?
  • В чем отличие выполнения функции flags без параметров и с параметром?
  • Назовите возможные причины ошибок, возникающих при открытии файлов для чтения и для записи.
  • Можно ли один и тот же файл одновременно открыть для записи и для чтения? Если да, то где будет находиться файловый указатель?
  • Страницы:

    Цель лекции: изучить использование алгоритмов обработки элементов файла в решении задач и научится приемам решения задач на обработку элементов файла на языке C++.

    Потоки для работы с файлами создаются как объекты следующих классов:

    ofstream – для вывода (записи) данных в файл;

    ifstream – для ввода (чтения) данных из файла;

    fstream – для чтения и для записи данных (двунаправленный обмен).

    Чтобы использовать эти классы, в текст программы необходимо включить дополнительный заголовочный файл fstream.h. После этого в программе можно определять конкретные файловые потоки, соответствующих типов.

    Создание файлового потока (объекта соответствующего класса) связывает имя потока с выделяемым для него буфером и инициализирует переменные состояния потока. Так как перечисленные классы файловых потоков наследуют свойства класса ios, то и переменные состояния каждого файлового потока наследуются из этого базового класса. Файловые классы являются производными от классов ostream (класс ofstream ), istream (класс ifstream ), stream (класс fstream ), они поддерживают описанный в предыдущих шагах форматированный и бесформатный обмен с файлами. Однако прежде чем выполнить обмен, необходимо открыть соответствующий файл и связать его с файловым потоком.

    Открытие файла в самом общем смысле означает процедуру, информирующую систему о тех действиях, которые предполагается выполнять с файлом. Работая с файловыми потоками с помощью библиотек ввода-вывода языка С++, удобнее пользоваться компонентными функциями соответствующих классов.

    Большинство средств управления потоковым вводом-выводом сосредоточены в классе ios, который является базовым для ostream и istream. По сути здесь находится управление связью между istream или ostream и буфером, используемым для операций ввода-вывода. Именно класс ios контролирует работу буфера обмена: как символы заносятся и как они считываются.

    Класс ios (iostream.h)

    Обеспечивает общие операции для ввода и вывода. Производные от него классы ( istream, ostream, iostream ) специализируют ввод-вывод с помощью операций форматирования высокого уровня. Класс ios является базовым для istream, ostream, fstreambase и strstreambase.

    Флаги форматирования – двоичные коды, управляющие форматом выводимых значений. В заголовочном файле iostream.h определено следующее перечисление, задающее флаги форматирования.

    Значения флагов форматирования файла iostream.h
    skipws 0х0001 Пропускает при вводе пробелы и разделители.
    left 0х0002 Выравнивание вывода влево.
    right 0х0004 Выравнивание вывода вправо.
    internal 0х0008 Дополнение после знака или указателя основания.
    dec 0х0010 Десятичное преобразование.
    oct 0х0020 Восьмеричное преобразование.
    hex 0х0040 Шестнадцатеричное преобразование.
    showbase 0х0080 Показывает в выводе индикатор основания.
    showpoint 0х0100 Показывает при выводе с плавающей точкой десятичную точку.
    uppercase 0х0200 Преобразует шестнадцатеричный вывод в верхний регистр.
    showpos 0х0400 Выводит с положительными числами символ '+'.
    scientific 0х0800 Добавляет к числам с плавающей точкой суффикс с показателем степени (E).
    fixed 0х1000 Для вывода чисел с плавающей точкой использует десятичную фиксированную точку.
    unitbuf 0х2000 После включения выводит все потоки.
    stdio 0х4000 После включения выводит stdout и stderr.

    Фактически в этом списке содержатся имена констант, определяющие флаги соответствующих назначений. Коду формата соответствует целый тип long. Изменить состояние флагов формата можно с помощью функции класса ios, имеющей прототип

    long setf(long flags);

    Например, чтобы установить флаг showbase в активный режим (включить) применительно к стандартному потоку вывода cout, используется оператор

    cout.setf(ios::showbase);

    Для установки флагов можно использовать побитовые операции. Например:

    cout.setf(ios::left|ios::hex);

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

    Функции класса ios
    Функция Прототип Описание
    bad int bad(); Ненулевое значение в случае ошибки.
    bitalloc static long bitalloc(); Получает новый флаг битового набора. Возвращаемое значение может использовать для установки, очистки и проверки флаги. Это флаги форматирования, определяемые пользователем.
    eof int eof(); В случае достижения конца файла возвращает ненулевое значение.
    fail int fail(); Не 0 при неуспешном выполнении операции с потоком.
    fill char fill(); Возвращает текущий символ-заполнитель потока.
    char fill(char); Заменяет значением параметра символ заполнения потока; возвращает ранее установленное значение символа заполнения.
    flags long flags(); Возвращает текущее значение флагов форматирования.
    long flags(long); Устанавливает флаги форматирования по значению параметра; возвращает ранее установленное значение флагов.
    good int good(); Возвращает ненулевое значение, если не установлен ни один флаг (ошибок нет).
    presicion int presicion(); Возвращает текущую точность числа с плавающей точкой.
    int presicion(int); Устанавливает точность вещественных чисел с плавающее точкой по значению параметра; Возвращает предыдущее значение параметра.
    rdbuf streambuf* rdbuf(); Возвращает указатель на streambuf, назначенный для данного потока.
    rdstate int rdstate(); Возвращает текущее состояние потока.
    setf long setf(long); Устанавливает флаги по значению параметра; возвращает ранее установленные флаги.
    sync_with_stdio sync_with_stdio; Смешивает файлы stdio и потоки iostreams. В новой программе этого использовать не следует.
    unseft long unseft(long); Очищает биты состояния потока, отмеченные параметром; возвращает предыдущее состояние битов.
    with int with(); Возвращает текущее значение ширины.
    int with(int); Устанавливает ширину, равную параметру; возвращает предыдущее значение параметра.
    gcount int gcount(); Возвращает число символов, извлеченных из потока последним обращением.
    get int get(); Получает следующий символ либо EOF, сохраняя их в буфере.
    int get(signed char*, int, char='\n'); Извлекает из входного потока символы и помещает их в буфер, на начало которого указывает char*. Передача завершается, если число принятых символов на 1 меньше второго параметра или встретился символ '\n'.
    getline iostream getline(signed char*, int, char='\n'); Извлекает из входного потока символы и помещает их в буфер, на начало которого указывает char*. Передача завершается, если число принятых символов на 1 меньше второго параметра или встретился символ '\n',который помещается в строку.
    ignore iostream ignore(int n, int delim); Пропускает n символов в потоке. При обнаружении delim останавливается (по умолчанию, delim=EOF ).
    peek int peek(); Возвращает следующий символ без извлечения из потока.
    putback iostream putback(char); Помещает символ обратно в поток.
    read read(signed char*, int); Извлекает из потока и помещает в символьный массив указанное число символов.
    seekg iostream seekg(long); Перемещает заданное число байт относительно текущей позиции для потока ввода. Можно задавать направление.
    telig Long telig(); Возвращает текущую позицию курсора. В случае неуспешного выполнения возвращает отрицательное число.
    flush ostream flush(); Флэширует внутренний буфер выходного потока.
    put ostream put(char); Помещает заданный параметром char символ в выходной поток.
    seekp ostream seekp (long); Устанавливает указатель записи выходного потока на абсолютную позицию, заданную параметром long.
    ostream seekp (long, seek_dir); Перемещает указатель текущей позиции выходного потока на число байтов, заданное первым параметром. Второй параметр задает точку отсчета (0 – начало; 1 – текущая позиция; 2 – конец потока)
    tellp long tellp(); Возвращает текущую позицию выходного потока.
    write ostream write (const signed, char *, int n); Помещает в выходной поток n символов из массива, на который указывает char *. Нуль-символы включаются в число переносимых символов.
    ostream write (const signed, char *, int n);

    Пример 1. Входной файл содержит следующую информацию: в первой строке натуральное число указывает количество чисел, далее следуют вещественные числа. Выведите в выходной файл только положительные числа из входного файла и их сумму.

    #include "stdafx.h"
    #include <iostream>
    using namespace std;
    #include <fstream> 
    int _tmain(int argc, _TCHAR* argv[]){
      int n,i=1; 
      float s, sum=0.0;
      // Открываем входной файл для ввода данных
      ifstream infile("in.txt"); 
      // Открываем выходной файл для вывода данных
      ofstream outfile("out.txt"); 
      // Проверка корректности открытия входного файла
      if (!infile) {cout << "Файл не открыт.\n";} 
        else {
          infile >> n; //Считываем количество чисел
          while (i++<=n){
            infile >> s; //Считываем вещественные числа
            if (s>0) {
                sum+=s;
                outfile << s <<"\n"; 
                //Выводим положительные числа  
                     }
            }
            outfile << sum; //Выводим сумму в выходной файл
            // Закрываем файлы 
            infile.close();
            outfile.close(); 
            cout << "Запись в файл завершена"; 
          }
      system("pause");
      return 0;
    }

    Пример 2. Дан текстовый файл. Выведите в выходной файл длину наибольшей строки и все строки такой длины.

    #include "stdafx.h"
    #include <iostream>
    using namespace std;
    #include <fstream> 
    #include <string.h>
    int _tmain(int argc, _TCHAR* argv[]){
      int maxlen=0, len; 
      char st[200],delim;
      //Связываем переменные с потоками
      ifstream infile; 
      ofstream outfile;
      // Открываем входной файл для ввода данных
      infile.open("in.txt"); 
      // Проверка корректности открытия входного файла
      if (!infile) {cout << "Файл не открыт.\n";} 
      else {
        //Поиск максимальной длины строк       
        while (!infile.eof()) {
          infile.getline(st,200,delim='\n');
          len=strlen(st); 
          if (len>maxlen) maxlen=len;
        }
        // Закрываем входной файл 
        infile.close();
      }
       //Открываем входной файл для ввода данных
       infile.open("in.txt"); 
       // Открываем выходной файл для вывода данных
       outfile.open("out.txt");
      // Проверка корректности открытия входного файла
      if (!infile) {cout << "Файл не открыт.\n";} 
      else {
        outfile<<"Длина наибольшей строки равна "<<maxlen<<"\n";
        //Поиск и вывод строк максимальной длины
        while (!infile.eof()) {
          infile.getline(st,200,delim='\n');
          len=strlen(st);
          if (len==maxlen) outfile <<st<<"\n";
        }
        // Закрываем файлы 
        infile.close(); 
        outfile.close(); 
        cout << "Запись в файл завершена";
      }  
      system("pause");
      return 0;
    }

    Ключевые термины

    Извлечение из потока – это процесс чтения данных из потока.

    Класс fstream – это поток для чтения и для записи данных (двунаправленный обмен).

    Класс ifstream – это поток для ввода (чтения) данных из файла

    Класс iosродительский класс для файловых потоков.

    Класс ofstream – это поток для вывода (записи) данных в файл.

    Помещение или включение в поток – это процесс вывода данных в поток.

    Поток – это абстрактное понятие, относящееся к любому переносу данных от источника к приемнику.

    Флаги форматирования – двоичные коды, управляющие форматом выводимых значений.

    Краткие итоги

  • Файловые потоки ofstream, ifstream, fstream наследуются из базового класса ios.
  • Класс ios контролирует работу буфера обмена.
  • Создание файлового потока связывает имя потока с выделяемым для него буфером и инициализирует переменные состояния потока.
  • Флаги форматирования управляют форматом выводимых значений.
  • Файловые потоки используются для обмена данными при решении задач.
  • Лабораторная работа 23. Решение задач на обработку файлов

    Цель работы: изучить использование алгоритмов обработки элементов файла в решении задач и научится приемам решения задач на обработку элементов файла на языке C++.

    При выполнении лабораторной работы для каждого задания требуется написать программу на языке С++, которая получает на входе строковые величины, являющиеся корректными именами входных и выходных файлов (при этом в программе следует предусмотреть проверку существования и корректности открытия используемых файлов). Ввод данных осуществляется из входных файлов с учетом требований к входным данным, содержащихся в постановке задачи. Ограничениями на входные данные является максимальный размер строковых данных и допустимый диапазон числовых типов в языке С++. При некорректном открытии файла программа должна завершить работу с выдачей на экран соответствующего сообщения. Считанные из файла данные обрабатываются в соответствии с условием задачи с помощью алгоритмов обработки данных файлов, после чего осуществляется вывод в выходной файл.

    Теоретические сведения.

    Ознакомьтесь с материалом лекции 23.

    Задания к лабораторной работе.

    Выполните приведенные ниже задания.

  • Заполните файл in.dat числами по закономерности: 1/2, 1/4, 2/6, 3/8, 5/16,… Считывая данные из in.dat, заполните файл out.dat квадратами чисел, попавших в отрезок [a, b].
  • Дан входной текстовый файл. Заполните выходной файл только теми строками, в которых ровно k символов ch.
  • Даны два входных текстовых файла. Сформируйте выходной файл из строк, полученных конкатенацией соответствующих по порядку строк входных файлов. Если один из входных файлов закончится раньше, то оставшиеся строки второго файла допишите без изменения.
  • Решите задачу на обработку файла. Использование дополнительного массива не предусматривается. Записать в файл N вещественных чисел. Найти наибольшее из значений модулей компонентов с нечетными номерами. Выведите результат на экран и в файл.
  • Указания к выполнению работы.

    Каждое задание необходимо решить в соответствии с изученными методами и алгоритмами обработки файлов в языке С++. В программном коде к каждой задаче следует выполнять чтение данных из существующих входных файлов (имя каждого файла вводится в виде строки символов и считается корректным с точки зрения организации файловой системы). Данные входных файлов необходимо обработать, применив алгоритмы обработки файлов. В задаче 4 нельзя использовать дополнительные массивы для хранения промежуточных данных. Вывод следует осуществить в выходной файл, имя которого вводится как строка символов с клавиатуры. Данные входного и выходного файлов необходимо дублировать на экране с соответствующими комментариями. Программу для решения каждого задания необходимо разработать методом процедурной абстракции, оформив комментарии к коду.

    Следует реализовать каждое задание в соответствии с приведенными этапами:

  • изучить словесную постановку задачи, выделив при этом все виды данных;
  • сформулировать математическую постановку задачи;
  • выбрать метод решения задачи, если это необходимо;
  • разработать графическую схему алгоритма;
  • записать разработанный алгоритм на языке С++;
  • разработать контрольный тест к программе;
  • отладить программу;
  • представить отчет по работе.
  • Требования к отчету.

    Отчет по лабораторной работе должен соответствовать следующей структуре.

  • Титульный лист.
  • Словесная постановка задачи. В этом подразделе проводится полное описание задачи. Описывается суть задачи, анализ входящих в нее физических величин, область их допустимых значений, единицы их измерения, возможные ограничения, анализ условий при которых задача имеет решение (не имеет решения), анализ ожидаемых результатов.
  • Математическая модель. В этом подразделе вводятся математические описания физических величин и математическое описание их взаимодействий. Цель подраздела – представить решаемую задачу в математической формулировке.
  • Алгоритм решения задачи. В подразделе описывается разработка структуры алгоритма, обосновывается абстракция данных, задача разбивается на подзадачи. Схема алгоритма выполняется по ЕСПД (ГОСТ 19.003-80 и ГОСТ 19.002-80).
  • Листинг программы. Подраздел должен содержать текст программы на языке программирования С++, реализованный в среде MS Visual Studio 2010.
  • Контрольный тест. Подраздел содержит наборы исходных данных и полученные в ходе выполнения программы результаты.
  • Выводы по лабораторной работе.
  • Ответы на контрольные вопросы.
  • Контрольные вопросы

  • Предусмотрены ли флаги форматирования для вводимых в файл значений? Почему?
  • С какой целью выделены как отдельные потоки ofstream, ifstream, fstream?
  • В чем отличие выполнения функции get без параметров и с тремя параметрами?
  • В чем отличие выполнения функции flags без параметров и с параметром?
  • Назовите возможные причины ошибок, возникающих при открытии файлов для чтения и для записи.
  • Можно ли один и тот же файл одновременно открыть для записи и для чтения? Если да, то где будет находиться файловый указатель?
  • Вернуться к учебному плану