Лабораторная работа 11
Работа с файлами
Постановка задачи
Имеется текстовый файл, содержащий произвольное количество строк. Длина каждой строки не превосходит 255 символов. Необходимо выполнить заданную обработку файла.
Варианты заданий
Варианты заданий приведены в табл. 1.11. 1
Таблица 1.11. 1
N | Задание |
В каждой строке исходного файла имеется произвольное количество чисел, записанных в форме f. Количество чисел в строке не превосходит 10. Сформировать новый файл, содержащий нормализованные числа исходного файла. Каждая строка файла нормализуется отдельно путем деления ее элементов на значение максимального элемента строки. | |
В каждой строке исходного файла имеется произвольное количество чисел, записанных в форме f. Сформировать новый файл, дописав в начало каждой строки исходного файла сумму ее элементов. | |
В каждой строке исходного файла имеется произвольное количество чисел, записанных в форме f. Сформировать новый файл, дописав в начало каждой строки исходного файла количество, содержащихся в ней чисел. | |
В каждой строке исходного файла имеется произвольное количество слов. Сформировать новый файл, дописав в каждую строку исходного файла количество, содержащихся в ней слов. | |
В файле хранится числовая матрица. В первой строке файла записаны два числа: количество строк и столбцов матрицы, а затем сама матрица. Сформировать новый файл, в котором должна храниться транспонированная матрица. | |
В файле хранится числовая матрица. В первой строке файла записаны два числа: количество строк и столбцов матрицы, а затем сама матрица. Вычислить для каждой строки произведение ее элементов. Результаты вычислений должны быть записаны в конец исходного файла в виде таблицы следующего вида: СТРОКА ПРОИЗВЕДЕНИЕ <номер строки> <вычисленное произведение> | |
В файле хранится числовая матрица. В первой строке файла записаны два числа: количество строк и столбцов матрицы, а затем сама матрица. Все отрицательные числа исходной матрицы заменить нулями. Полученную матрицу записать в новый файл. | |
Имеется текстовый файл, содержащий не более 100 строк. Выполнить сортировку строк файла в прямом лексикографическом порядке. Результаты сортировки записать в новый файл. |
Продолжение табл. 1.11. 1
N | Задание |
В файле хранится числовая матрица. В первой строке файла записаны два числа: количество строк (N <= 20) и столбцов матрицы (M<=5), а затем сама матрица. Вычислить для каждого столбца сумму его элементов. Результаты вычислений должны быть записаны в конец исходного файла в виде таблицы следующего вида: СТОЛБЕЦ СУММА <номер столбца> <вычисленная сумма> | |
Имеется текстовый файл, содержащий не более 100 строк. Выполнить сортировку строк файла в обратном лексикографическом порядке. Результаты сортировки записать в новый файл. | |
Имеется текстовый файл, содержащий действительные числа. Количество чисел в строке может быть любым. Количество строк не превосходит 100. Для каждой строки вычислить сумму содержащихся в ней чисел, а затем выполнить сортировку строк файла в порядке возрастания суммы. Результаты сортировки записать в новый файл. | |
Имеется текстовый файл, содержащий действительные числа. Количество чисел в строке может быть любым. Количество строк не превосходит 100. Для каждой строки вычислить сумму содержащихся в ней чисел, а затем выполнить сортировку строк файла в порядке убывания суммы. Результаты сортировки записать в новый файл. | |
В каждой строке записано произвольное количество чисел, записанных в форме f. Сформировать новый файл, дописав в конец каждой строки исходного файла значение ее максимального элемента. | |
В каждой строке записано произвольное количество чисел, записанных в форме f. Сформировать новый файл, дописав в начало каждой строки исходного файла значение минимального элемента этой строки. | |
В файле хранится числовая матрица. В первой строке файла записаны два числа: количество строк и столбцов матрицы, а затем сама матрица. Вычислить для каждой строки сумму ее положительных элементов. Результаты вычислений должны быть записаны в конец исходного файла в виде таблицы следующего вида: СТРОКА СУММА ПОЛОЖИТЕЛЬНЫХ ЭЛЕМЕНТОВ <номер строки> <вычисленная сумма> | |
В каждой строке записано произвольное количество чисел, записанных в форме f. Сформировать новый файл, дописав в каждую строку исходного файла сумму ее положительных элементов. | |
В файле хранится числовая матрица. В первой строке файла записаны два числа: количество строк и столбцов матрицы, а затем сама матрица. Сформировать новый файл, содержащий только те строки исходной матрицы, сумма чисел в которых превышает заданную величину. |
Окончание табл.1.11. 1
В файле хранится числовая матрица. В первой строке файла записаны два числа: количество строк и столбцов матрицы, а затем сама матрица. Сформировать новый файл, содержащий только те строки исходной матрицы, в которых отсутствуют отрицательные числа. | ||
В каждой строке записано произвольное количество чисел, записанных в форме f. Сформировать новый файл, переписав в него только те строки, в которых отсутствуют положительные числа. | ||
В каждой строке файла имеется произвольное количество чисел, записанных в форме f. Сформировать новый файл, содержащий нормализованные числа исходного файла. Каждая строка нормализуется путем деления ее элементов на полусумму значений максимального и минимального элемента строки. | ||
В каждой строке записано произвольное количество чисел, записанных в форме f. Для каждой строки вычислить сумму ее элементов. Дописать в конец файла строку с максимальным значением этой суммы. | ||
В файле хранится числовая матрица. В первой строке файла записаны два числа: количество строк и столбцов матрицы, а затем сама матрица. Все отрицательные числа исходной матрицы возвести в квадрат. Полученную матрицу записать в новый файл. | ||
Дан текстовый файл. Сформировать новый файл, состоящий из строк исходного файла. Порядок строк в новом файле должен быть обратным по отношению к порядку строк в исходном файле. | ||
Дан текстовый файл. Записать в новый текстовый файл все строки исходного файла, которые в качестве фрагмента содержат строку Str. | ||
В файле хранится числовая матрица. В первой строке файла записаны два числа: количество строк и столбцов матрицы, а затем - сама матрица. Для каждой строки матрицы вычислить корень квадратный из суммы квадратов ее элементов. Результаты вычислений необходимо записать в новый файл. | ||
В файле хранится числовая матрица. В первой строке файла записаны два числа: количество строк(N <= 10) и столбцов матрицы(M <= 15), а затем - сама матрица. Для каждого столбца матрицы вычислить корень квадратный из суммы квадратов ее элементов. Результаты вычислений необходимо записать в новый файл. |
Методические указания по выполнению лабораторной работы
Приведем ряд рекомендаций, которые могут быть полезными при выполнении настоящей работы.
1. Требуемую обработку следует оформить в виде функции пользователя. Входной и выходной файлы в эту функцию целесообразно передавать с помощью аппарата формальных и фактических параметров, а подготовительные файловые операции предпочтительнее выполнять в клиентском коде этой функции. К таким операциям относятся следующие операции: открытие и закрытие файла.
2. В ряде задач в файле хранится числовая матрица. Это задачи 5 – 7, 9, 15, 17, 18, 22, 25 и 26. Первая строка файла в этих задачах содержит два числа, которые определяют количество строк и столбцов матрицы. Обработка файла может быть построена следующим образом. Вначале из файла читаются с помощью функции fscanf() два первых числа, которые записываются в две целочисленные переменные n и m. Затем следует организовать вложенные арифметические циклы.
3. В задачах 8, 10 - 12 необходимо выполнить сортировку строк файла. Для выполнения сортировки можно воспользоваться любым способом. Например, можно использовать простейший способ – метод пузырьковой сортировки. В качестве примера ниже приводится функция для сортировки строк в порядке их возрастания (bibble).
#define MAXLENGTH 128
void bibble(char arr[][MAXLENGTH + 1], int n)
{
int i, j;
char buf[MAXLENGTH + 1];
for (i = 1; i < n; i++)
{
for (j = n - 1; j >=i; --j)
{
if(strcmp(arr[j - 1], arr[j]) < 0)
{
strcpy(buf, arr[j - 1]);
strcpy(arr[j - 1], arr[j]);
strcpy(arr[j], buf);
}
}
}
}
4. В ряде задач в файле находится произвольное количество строк, каждая из которых содержит произвольное количество чисел. К таким задачам относятся задачи 1 – 3, 13, 14, 16, 19 – 21. В этом случае обработка может состоять из вложенных итерационных циклов. Во внешнем цикле можно читать очередную строку, а во внутреннем цикле выполнять обработку строки с помощью функции strtod().
5. В процессе решения поставленной задачи следует продумать, какие структуры данных могут потребоваться для ее решения. В первую очередь, это относится к тем задачам, в которых в файле хранится матрица. В этих задачах необходимо выяснить требуется или нет при ее решении использовать двумерный массив. В ряде случаев необходимости в их применении нет. К числу таких задач относится, например задача 25. В этой задаче необходимо вычислить корень квадратный из суммы элементов строки числовой матрицы, хранящейся в текстовом файле. Здесь структура программы – вложенные арифметические циклы. Внутренний цикл должен выполнять суммирование квадратов элементов очередной строки, а внешний цикл – вычисляет корень квадратный из накопленной внутренним циклом суммы. Особенностью этой задачи является то положение, что прочитанное из файла число может сразу же быть обработано (просуммировано с квадратом) и необходимости в его хранении для последующей обработки нет. Совсем иначе дело обстоит при решении задачи 26. Здесь необходимо решить практически ту же задачу, что и в варианте 25, но применительно к столбцам матрицы. Здесь придется вначале прочитать весь файл в матрицу (двумерный числовой массив) и только затем приступить к его обработке.
Справочные материалы
При работе с внешними устройствами при программировании на языке Си следует использовать библиотечные функции. Библиотечные функции языка Си, предназначенные для работы с внешними устройствами можно разделить на две категории:
· низкоуровневые функции,
· потоковые функции.
Низкоуровневые библиотечные функции учитывают особенности той среды, в которой выполняется программа. Это позволяет повысить их эффективность по сравнению с потоковыми функциями. Недостатком таких функций является ухудшение переносимости программ. Такие функции не поддерживаются стандартом языка Си.
Потоковые функции нашли более широкое применение по сравнению с низкоуровневыми функциями. Этому способствовало то обстоятельство, что эти функции в стандарт языка Си. Они включены в стандартную библиотеку, которая является составной частью стандарта языка Си. В литературе рекомендуется использовать преимущественно те функции, которые входят в стандартную библиотеку языка Си. Ограничимся рассмотрением только потоковых библиотечных функций.
Приведем описание стандартных подпрограмм, которые следует использовать при работе с файлами. Остановимся на некоторых понятиях, существенных для работы с потоковыми библиотечными функциями.
Понятие потока
Поток – это своего рода обобщенное устройство ввода – вывода. Это понятие введено с целью обеспечить независимость программирования операций ввода – вывода от следующих факторов:
· конкретного типа внешнего устройства,
· среды, в которой выполняется программа.
Все потоки ведут себя похожим образом. Их работа не учитывает особенности физического устройства. В этой связи функция, выполняющая чтение из дискового файла, может использоваться и для ввода с консоли. Потоки бывают двух категорий:
· текстовые,
· двоичные.
Текстовый поток
Текстовый поток – это последовательность символов, организованная в строки. Каждая строка должна заканчиваться символом новой строки: ‘\n’. Однако в конце последней строки этот символ не является обязательным. В зависимости от среды, в которой происходит выполнение программы, при использовании текстового потока может иметь место преобразование символов. Например, при записи в среде DOS или Windows символ ‘\n’ преобразуется в последовательность символов CRLF.
Таким образом, при использовании текстового потока может и не иметь место однозначное соответствие между символами, которые записываются (читаются) и теми символами, которые хранятся на внешнем устройстве.
Кроме того, при использовании текстового потока для чтения особым образом обрабатывается символ конца файла. В таблице кодов ASCII этот символ имеет код 0x1A.
Двоичный поток
Двоичный поток – это последовательность байтов, которая взаимно однозначно соответствует байтам на внешнем устройстве, причем никаких преобразований символов не происходит; отсутствуют символы, которые играют особую роль. Все символы обрабатываются одинаково. Количество символов, которые записываются (читаются) совпадает с количеством символов, хранящихся на внешнем устройстве.
Файлы в языке СИ
В языке Си файлом называется любое внешнее устройство, начиная от дискового файла и кончая терминалами и принтерами. Поток связывается с определенным файлом при выполнении операции открытия. Как только файл будет открыт, можно выполнять обмен данными между ним и программой.
Файл отключается от определенного потока при выполнении операции закрытия. При закрытии файла, открытого для записи, содержимое (если оно имеется) связанного с ним потока записывается на внешнее устройство. Этот процесс, называемый дозаписью потока гарантирует, что все данные будут записаны на внешнее устройство.
Указатель файла
У каждого файла, связанного с потоком, имеется специальная управляющая структура, содержащая сведения о файле. Эта структура имеет тип FILE. Этот тип объявлен в заголовочном файле stdio.h. Для каждого файла, с которым должна работать программа должен существовать свой указатель файла. Указатель файла – это указатель на структуру типа FILE. Указатель файла представляет файл во всех операциях ввода – вывода..
Функция fopen
Объявление этой функции имеет следующий вид.
#include<stdio.h>
FILE* fopen(const char * filename, const char * mode);
Эта функция открывает поток и связывает с ним определенный файл. Первый параметр (filename) рассматриваемой функции определяет открываемый файл. Второй параметр функции (mode) задает режим, в котором должен быть открыт файл.
В случае успеха функция вернет указатель типа FILE* на созданную структуру данных. Этот указатель может использоваться файловыми функциями для выполнения операций ввода – вывода. В случае возникновения ошибки функция fopen() вернет нулевой указатель.
В следующем фрагменте программного кода функция используется для открытия файла с именем file1.txt в режиме записи. Предполагается, что файл находится в текущем каталоге (иначе необходимо указывать путь к каталогу). Во фрагменте используется обычный прием, который состоит в проверке значения, возвращаемого функцией fopen().
FILE* fp;
if ((fp = fopen(“file1.txt”, “w”)) == NULL)
{
printf(“Не могу открыть файл file1.txt”);
exit(1);
}
Возможные режимы открытия потоков представлены в таблице 1.11. 2.
Таблица 1.11. 2.
Режим | Пояснение |
r | Открыть текстовый поток и связать его с существующим файлом |
w | Открыть текстовый поток и связать его с вновь созданным файлом |
a | Открыть текстовый файл в режиме дозаписи. Если файл еще не существует, то он будет создан. |
rb, wb и ab | Отличаются соответственно от режимов r, w и a только тем, что открывают двоичный поток. |
r+, w+ и a+ | Отличаются соответственно от режимов r, w и a только тем, что поток открывается в режиме чтения / записи. |
r+b, w+b и a+b | Отличаются соответственно от режимов rb, wb и ab только тем, что поток открываются в режиме чтения / записи. |
Функция fclose
Объявление этой функции имеет следующий вид.
#include<stdio.h>
int fсlose(FILE* stream);
Функция fclose() закрывает поток stream. Перед закрытием потока все связанные с ним буферы сбрасываются. При успешном выполнении функция fclose() возвращает 0, а в случае ошибки – EOF.
Функция feof
Объявление рассматриваемой функции имеет следующий вид:
#include<stdio.h>
int feof(FILE* stream);
Функция feof() проверяет, достигнут ли конец файла при выполнении очередной операции чтения. Параметр stream является указателем на поток, с которым работает файл.
Если указатель текущей позиции файла установлен на конец файла, то функция feof() вернет ненулевое значение, в противном случае возвращается нуль.
Стандартные потоки
В начале выполнения программы автоматически открываются три стандартных потока (см. таблицу 1.12. 3)
Таблица 1.11. 3.
Поток | Файловый указатель | Внешнее устройство |
Ввода | stdin | клавиатура |
Вывода | stdout | Экран дисплея |
Ошибок | stderr | Экран дисплея |