пятница, 1 февраля 2013 г.

[Информатика] Файлы текст чтение


Файлы.
Текстовые файлы.
Чтение данных из текстового файла.
Рассмотрим чтение из файла. Открывается файл для чтения с помощью процедуры
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  
Подпись: 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.
В текстовом файле записано несколько строк. Каждая строка содержит несколько целых чисел, отделённых друг от друга одним или несколькими пробелами. Написать программу, которая посчитает сумму последних чисел в строках (то есть в каждой строке берётся последнее число и складывается с суммой). Имя файла вводится в поле ввода.
Для проверки работоспособности программы создайте текстовый файл с помощью текстового редактора (например, Блокнота).