Файлы.
Текстовые файлы.
Чтение данных из
текстового файла.
Рассмотрим
чтение из файла. Открывается файл для чтения с помощью процедуры
Reset(f)
Обратите внимание, что при открытии файла для чтения из него, файл должен существовать на
диске, если его нет, то появится сообщение об ошибке и выполнение программы
прервётся.
Если
открытие прошло успешно, то курсор (указатель) помещается в начало открытого
файла, т.е. на первую строку, которую мы можем прочитать в строковую переменную
s при помощи
процедуры
ReadlLn(f, s)
При
выполнении данного оператора в переменную sзаписывается первая строка, курсор помещается на начало
второй строки. Если снова выполнить оператор ReadlLn , то в переменную считается вторая строка, а курсор
переместится в начало следующей строки и т.д. После того, как с файлом
поработали, его необходимо закрыть (так же, как и при записи в файл) с помощью
процедуры CloseFile(f).
Рассмотрим
пример процедуры, которая записывает первую строку файла 'my.txt' в поле Memoс именемmemEx1.
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f:TextFile;
s:string;
begin
AssignFile(f,'my.txt');//Ставим в
соответствие файл и файловую переменную
Reset(f);
//Открываем файл для чтения
ReadLn(f, s);//Читаем из
файла строку
memEx1.Lines.Append(s); //Записываем
строку в поле вывода
CloseFile(f); // Закрываем
файл
end;
При запуске
этой программы на выполнение в поле вывода всегда будет записываться только
одна строка – первая. Чтобы считать несколько строк из файла, необходимо
воспользоваться циклом. Например, следующая процедура считает и поместит в поле
Мемо 5 строк из файла 'my.txt'.
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f:TextFile;
s:string;
i:integer;
begin
AssignFile(f,'my.txt');//Ставим в
соответствие файл и файловую переменную
Reset(f);
//Открываем файл для чтения
For
i:=1 to 5 do //выполняем 5 раз
begin
ReadLn(f, s);//Читаем из
файла строку
memEx1.Lines.Append(s); //Записываем
строку в поле вывода
end;
CloseFile(f);
// Закрываемфайл
end;
Как уже было
сказано ранее, текстовые файлы – это файлы последовательного доступа, т.е.
нельзя сразу обратиться к конкретной строке, а необходимо предварительно
считать все предыдущие. Например, если необходимо вывести в поле вывода только
пятую строку, то надо предварительно считать 4 строки. Для этого можно
воспользоваться оператором ReadLn без указания переменной, в которую считываем,
т.е. воспользоваться следующей формой оператора ReadLn(f)
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f:TextFile;
s:string;
i:integer;
begin
AssignFile(f,'my.txt');//Ставим в
соответствие файл и файловую переменную
Reset(f);
//Открываем файл для чтения
For
i:=1
to
4 do
//выполняем4раза
ReadLn(f);//пропускаемстроку
Readln(f, s);//Читаем из
файла строку (пятую)
memEx1.Lines.Append(s); //Записываем
строку в поле вывода
CloseFile(f);
// Закрываемфайл
end;
В этом
примере оператор ReadLn(f) просто
переносит указатель на начало следующей строки, не считывая никаких данных.
Мы не всегда
можем знать, сколько именно строк в файле. Как же считать все строки из файла,
не зная сколько их? Решить эту задачу можно с помощью булевской функции EOF(f)(от
английского EndOfFile–конец файла).
Данная функция принимает значение «истина»,
если в момент её вызова курсор находится
в конце файла и «ложь» ‑
в противном случае. Приведём пример процедуры, которая все строки файла
перепишет в поле Memo.
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f:TextFile;
s:string;
begin
AssignFile(f,'my.txt');//Ставим в
соответствие файл и файловую переменную
Reset(f);
//Открываем файл для чтения
WhilenotEOF(f)
do//поканеконец файла
begin
ReadLn(f, s);//Читаем из
файла строку
memEx1.Lines.Append(s); //Записываем
строку в поле вывода
end;
CloseFile(f);
// Закрываемфайл
end;
Обратите
внимание, что во всех задачах мы использовали оператор ReadLn, а не Read. Так,
например, если в последней задаче использовать оператор Readвместо ReadLn, то
программа никогда не закончит свою работу. Дело в том, что оператор Read считает данные в строку, но не переведёт курсор в
начало следующей строки, а оставит его в конце первой строки. Следующий
оператор Read считает в
переменную пустую строку, так как в конце строки больше нет данных, и снова
курсор останется на месте и т.д. Таким образом, курсор никогда не попадёт в
конец файла и соответственно программа не выйдет из цикла. Следовательно, если
данные из файла считываются в строку, то надо использовать оператор ReadLn.
Кстати, а
можно ли выяснить, что курсор находится в конце
строки? Да, для этого служит другая булевская функция EOLN(f)(от
английского EndOfLiNe– конец
строки). Не трудно догадаться, что данная функция принимает значение «истина», если в момент её вызова
курсор находится в конце строки и «ложь» ‑ в противном случае.
Мы рассмотрели,как
работать с текстовым файлом, если нам необходимо считывать из файла данные,
которые интерпретируются как строки. Однако если в файле содержатся данные, которые
представляют из себя числа (как целые, так и вещественные), которые отделены
друг от друга одним или несколькими пробелами, то можно организовать работу
иным способом. В этом случае данные можно считывать сразу в переменные
численного типа (целые или вещественные). Посмотрим на примере, как это можно
сделать.
10
7 25
14
1 8 17
24
27 17
11
12
34 45
|
Если сразу
после открытия файла для чтения, мы воспользуемся оператором Read(f,x),
где f– файловая переменная,
x - переменная
целого типа,
то в
переменную x будет
записано число 10, а курсор
остановится сразу после 0
перед разделителем (в данном случае пробелом). При выполнении оператораRead(f,x) ещё раз произойдёт следующее – сначала будут
пропущены все разделители (пробелы), и курсор остановится перед числом 7, затем
число 7 запишется в переменную x, а курсор
остановится после 7 перед очередным разделителем (пробелом). При выполнении
оператораRead(f,x) третий раз произойдёт следующее – сначала
будут пропущены все разделители (пробелы), и курсор остановится перед числом
25, затем число 25 запишется в переменную x, а курсор остановится после 5 перед очередным
разделителем (в данном случае концом строки). Таким образом, оператор Read(f,x) (если xявляется численной переменной) работает следующим
образом: пропускаются все разделители (сколько бы их не было) до достижения
данных, считываются данные до следующего разделителя, данные интерпретируются
как число и записываются в численную переменную, а курсор останавливается перед
разделителем.
Рассмотрим
пример
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f:TextFile;
s:string;
x,
i,
k:integer;
begin
AssignFile(f,'my.txt');//Ставим в
соответствие файл и файловую переменную
Reset(f);
//Открываем файл для чтения
k:=0;
For i:=1 to
5do//выполнитьпятьраз
begin
Read(f, x);//Читаем очередное
число
k:=k+x; //прибавляем
его к сумме
end;
CloseFile(f);
// Закрываемфайл
end;
После
выполнения этой процедуры в переменнойkбудет 57
- сумма первых пяти чисел 10, 7, 25,
14 и 1. Как можно заметить, оператор Read(f, x) считывал
численные данные в численную переменную, пропуская любое количество
разделителей, стоящих между данными. В качестве разделителей могут выступать
как пробелы, так и концы строк.
Что
произойдёт, если в приведённом примере заменить оператор Read(f, x) на ReadLn(f, x)?Оператор ReadLn(f, x) работает
почти так же, как и оператор Read(f, x).
Единственное его отличие заключается в том, что после считывания данных в
переменную, курсор не остаётся после данных, а перемещается на начало следующей
строки.
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f:TextFile;
s:string;
x,
i,
k:integer;
begin
AssignFile(f,'my.txt');//Ставим в
соответствие файл и файловую переменную
Reset(f);
//Открываем файл для чтения
k:=0;
For i:=1 to
5do//выполнитьпятьраз
begin
ReadLn(f, x);//Читаем очередное
число
k:=k+x; //прибавляем
его к сумме
end;
CloseFile(f);
// Закрываемфайл
end;
После
выполнения этойпроцедуры в переменнойkбудет 86
- сумма чисел, стоящих в начале первых пяти строк 10, 14, 24, 27 и 11.
Часто
возникает задача получить числа из какой-то одной строки, например, посчитать
сумму чисел в первой строке, а количество чисел в строке нам не известно.С
учётом сказанного выше кажется логичным использовать здесь функцию EOLN(f).И в данном случае процедура, решающая нашу задачу
могла бы выглядеть так
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f:TextFile;
s:string;
x,
k:integer;
begin
AssignFile(f,'my.txt');//Ставим в
соответствие файл и файловую переменную
Reset(f);
//Открываем файл для чтения
k:=0;
WhilenotEOLN(f)
do//поканеконец строки
begin
Read(f, x);//Читаем очередное
число
k:=k+x; //прибавляем
его к сумме
end;
CloseFile(f);
// Закрываемфайл
end;
После
выполнения этой процедуры в переменнойkдолжно быть 42
- сумма чисел из первой строки 10, 7,
25. Однако такой результат будет не всегда. Почему же может быть иной
результат. Ответ зависит от того, есть ли после последнего числа в строке
пробелы или нет. Если пробелов нет, то результат будет соответствовать
ожиданию.
Давайте
рассмотрим, что произойдёт, если после числа 25 в нашем примере будет стоять пробел. В этом случае, после
того, как тело цикла выполнится в третий раз и считается число 25, курсор остановится после цифры 5 перед пробелом. Произойдёт вызов
функции EOLN(f). Функция
выдаст результат «ложь», так
как курсор стоит не в конце строки (вспомним, после курсора стоит пробел), а,
следовательно, выход из цикла не состоится и снова выполнится оператор Read(f, x), который
пропустит все разделители (в нашем случае пробел и конец строки) и считает
число из следующей строки. То есть цикл продолжит выполняться и в переменной k окажется не сумма чисел из первой строки, а сумма
чисел из нескольких строк (из скольких конкретно зависит от того, когда после
последнего числа в строке не будет пробелов).
Для того,
чтобы избежать подобных проблем необходимо причтении чисел из файла использовать вместо функции EOLN(f) функцию SeekEOLN(f).Функция SeekEOLN(f)сначала
пропускает все пробелы, а потом проверяет, стоит ли курсор в конце строки. Если
мы перепишем вышеприведённый пример, заменив функцию EOLN(f) на функцию SeekEOLN(f), то
программа будет работать верно, всегда, вне зависимости от того стоят ли после
последнего числа в строке пробелы или нет.
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f:TextFile;
s:string;
x,
k:integer;
begin
AssignFile(f,'my.txt');//Ставим в
соответствие файл и файловую переменную
Reset(f);
//Открываем файл для чтения
k:=0;
WhilenotSeekEOLN(f)
do//поканеконец строки
begin
Read(f, x);//Читаем очередное
число
k:=k+x; //прибавляем
его к сумме
end;
CloseFile(f);
// Закрываемфайл
end;
Аналогично,
при работе с числами вместо функции EOF(f) надо
применять функцию SeekEOF(f).Данная
функция пропускает не только пробелы, но и концы строк.
Например,
если необходимо написать процедуру, которая посчитает сумму всех чисел в файле,
то она может выглядеть так
procedure TfrmEx1.btnEx1Click(Sender: TObject);
var
f:TextFile;
s:string;
x,
k:integer;
begin
AssignFile(f,'my.txt');//Ставим в
соответствие файл и файловую переменную
Reset(f);
//Открываем файл для чтения
k:=0;
WhilenotSeekEOF(f)
do//поканеконецфайла
begin
Read(f, x);//Читаем очередное
число
k:=k+x; //прибавляем
его к сумме
end;
CloseFile(f);
// Закрываемфайл
end;
При чтении
данных из файла необходимо руководствоваться следующим правилом:
Если данные
из файла читаются как строки,
то следует использовать функции EOLN(f) и EOF(f), если
данные из файла читаются как числа,
то следует использовать функции SeekEOLN(f) и SeekEOF(f).
Если при
считывании в численную переменную в файле окажутся не численные данные, то
возникнет ошибка и работа программы прервётся. Так же произойдёт ошибка, если в
целую переменную попытаться считать вещественное число, или при считывании в
вещественную переменную, в числе в файле разделитель целой и дробной части
будет не точка (а, например, запятая).
Задачи.
Задача 1.
Написать
программу, которая посчитает количество строк в текстовом файле. Имя файла
вводится в поле ввода.
Для проверки
работоспособности программы создайте текстовый файл с помощью текстового
редактора (например, Блокнота).
Задача
2.
Написать
программу, которая определит, сколько символов содержит самая длинная строка в
текстовом файле. Имя файла вводится в поле ввода.
Для проверки
работоспособности программы создайте текстовый файл с помощью текстового
редактора (например, Блокнота).
Задача
3.
Написать
программу, которая найдёт самую длинную строку в текстовом файле и выведет её
содержимое в надпись (label).Если таких
строк несколько, то вывести первую из них. Имя файла вводится в поле ввода.
Для проверки
работоспособности программы создайте текстовый файл с помощью текстового
редактора (например, Блокнота).
Задача
4.
Написать программу,
которая перепишет в поле Memoте строки из
текстового файла, в которых количество слов чётно. Имя файла вводится в поле
ввода.
Для проверки
работоспособности программы создайте текстовый файл с помощью текстового
редактора (например, Блокнота).
Задача
5.
В текстовом
файле записано несколько строк. Каждая строка содержит несколько целых чисел,
отделённых друг от друга одним или несколькими пробелами. Написать программу,
которая посчитает сумму чисел в той строке, количество чисел в которой
минимально. Если таких строк несколько, то вывести сумму чисел в последней из
них. Имя файла вводится в поле ввода.
Для проверки
работоспособности программы создайте текстовый файл с помощью текстового
редактора (например, Блокнота).
Задача
6.
В текстовом
файле записано несколько строк. Каждая строка содержит несколько целых чисел,
отделённых друг от друга одним или несколькими пробелами. Написать программу,
которая посчитает сумму последних чисел в строках (то есть в каждой строке
берётся последнее число и складывается с суммой). Имя
файла вводится в поле ввода.
Для проверки
работоспособности программы создайте текстовый файл с помощью текстового
редактора (например, Блокнота).