Практическое занятие № 7
Тема: "Работа с файлами"
Цель работы: получить практические навыки по работе с папками и файлами, обработке текстовых файлов и использованию диалдогов для работы с файлами
Ход работы
Задача № 1
Создайте форму вида:

Указания: Для формы задайте свойства: BorderStyle=bsSingle, BorderIcons - biMaximized = false, Caption = Обработка файлов, Position= poDesktopCenter.
Нанесите на форму 4 компонента Label для отображения надписей на форме. Для четвертой надписи (на рисунке она красная) задайте свойства: Caption - Очистить, Alignment = alCenter, Font = красный.
Для ввода имен файлов нанесите на форму два поля Edit и разместите их под 2 и 3 надписями.
Для отображения содержимого файлов нанесите на форму три компонента Memo и задайте свойства: Lines - очистить, ReadOnly = true.
Добавьте на форму две кнопки Button. Для кнопок задайте свойство Caption. Для 2 кнопки задайте свойство Enabled = false.
Кнопка "Загрузить файл" выводит диалог выбора текстового файла. После выбора содержимое файла загружается в левое текстовое поле.
Указания: нанесите на форму компонент OpenDialog (Dialogs) и задайте свойство Filter = Текстовые файлы|*.txt
В коде опишем глобальную переменную. Она будет сохранять имя исходного файла из диалога.
f:string;
В событии OnClick кнопки введите код:
procedure TForm1.Button1Click(Sender: TObject);
begin
//если файл не выбран, то завершаем работу
if not (OpenDialog1.Execute) then Exit;
//записываем в глобальную переменную имя выбранного файла
f := OpenDialog1.FileName;
//в левое многострочное поле загружаем содержимое выбранного файла
Memo1.Lines.LoadFromFile(f);
//в надписи вверху формы отображаем имя файла (без полного пути)
Label4.Caption := ExtractFileName(f);
//разблокируем 2 кнопку
Button2.Enabled := true;
end;
Для проверки работы функции подготовьте текстовый файл, в который введите на разных строках произвольные положительные, нулевые и отрицательные числа.
Кнопка "Обработать файл" позволяет обработать содержимое исходного текстового файла по правилу: положительные и нулевые элементы записываются в первый файл, отрицательные - во второй. Имена файлов указываются в полях над многострочными полями. Сами файлы сохраняются в папку, заданную с помощью диалога выбора папки.
Указания: для отображен диалога выбора папки подключите модуль FileCtrl. Для 2 кнопки в событии OnClick напишем код:
procedure TForm1.Button2Click(Sender: TObject);
var
//описываем экземпляры класса для считывания исходного файла
//и создание двух новых
f1,f2,f3: TStringList;
//описываем переменную для записи имени папки из диалога
path: string;
//описываем переменную для счетчика цикла
i:integer;
begin
//если не заполненны поля Edit1 или Edit2 (имена новых файлов)
if (Edit1.Text = '') or (Edit2.Text ='') then
begin
//выводим сообщение об ошибке
//функция chr(13) используется для переноса
//текста сообщения на красную строку
Application.MessageBox(Pchar('Недостаточно введенной информации.'+chr(13)+
'Укажите в полях имена файлов.'),
'Ошибка ввода',
MB_OK+MB_IconError);
//ставим курсор в поле с именем первого файла
Edit1.Setfocus;
//подпрограмма завершает работу
Exit;
end;
//переменная f1 создается в памяти и связывается с исходным файлом
f1:=TStringList.Create;
f1.LoadFromFile(f);
//переменные f2, f3 создаются в памяти для обработки исходного файла
f2:=TStringList.Create;
f3:=TStringList.Create;
//организуем цикл до конца исходного файла
//переменная f1 связана с исходным файлом
for i:=0 to f1.Count-1 do
begin
//если число в i-й строке файла положительное
if StrToFloat(f1.Strings[i])>0 then
//оно записывается в первый выходной файл
f2.Add(f1.Strings[i])
//иначе, если число отрицательное
else
//оно записывается во второй выходной файл
f3.Add(f1.Strings[i]);
end;
//перед сохранением полученных файлов отображаем диалог выбора имени папки,
//в которую файлы будут сохранены
//по умолчанию укажем в качестве места для сохранения папку с программой
path:=ExtractFilePath(Application.ExeName);
//вызываем диалог выбора имени папки и записываем имя папки в переменную path
SelectDirectory('Выберите папку','',path, [sdNewUI, sdNewFolder]);
//сохраняем созданные в памяти классы в папку,
//имя которой находится в переменной path
//под именами, заданными в текстовых полях
f2.SaveToFile(path+'\'+Edit1.Text);
f3.SaveToFile(path+'\'+Edit2.Text);
//загружаем полученные файлы во 2 и 3 многострочные поля
Memo2.Lines.LoadFromFile(path+'\'+Edit1.Text);
Memo3.Lines.LoadFromFile(path+'\'+Edit2.Text);
//удаляем из памяти созданные экземпляры классов
f1.Free;
f2.Free;
f3.Free;
end;
Задача № 2
Создайте форму, показанную на рисунке:

Поля-счетчики должны заполняться с шагом 0.1.
Указания: для формы задайте свойства: Align=alCustom, BorderStyle=bsSingle, BorderIcons-biMaximized=false, Caption= Работа с файлами, Position=poDesktopCenter.
Для создания первого счетчика нанесите на форму компонент Edit (Standard) и задайте для него свойства ReadOnly=true, Text=0. Нанесите на форму компонент Updown (Win32), задайте свойство Max=1000. Разместите компонент справа от текстового поля.
Для того, чтобы счетчик заполнялся дробными значениями с шагом 0.1 в событии OnClick компонента Updown напишите код:
procedure TForm1.Updown1Click(Sender: TObject; Button: TUdbtnType);
begin
Edit1.Text:=FloatToStr(Updown1.Position*0.1);
end;
Повторите эту же операцию для создания второго и третьего счетчиков. При этом код для второго компонента UpDown будет иметь вид:
procedure TForm1.Updown2Click(Sender: TObject; Button: TUdbtnType);
begin
Edit2.Text:=FloatToStr(Updown2.Position*0.1);
end;
Для третьего компонента Updown код имеет вид:
procedure TForm1.Updown3Click(Sender: TObject; Button: TUdbtnType);
begin
Edit3.Text:=FloatToStr(Updown3.Position*0.1);
end;
Нанесите на форму компонент Memo (Standard) и задайте свойства: Alignment=taCenter, Font=Courier New, Lines очистить, ReadOnly=true, ScrollBars=ssNone.
Программное отображение вертикальной полосы прокрутки
По умолчанию в поле Memo нет полосы прокрутки, но как только текст в поле не помещается, должна отображаться вертикальная полоса. Как только текст помещается – исчезает.
Для реализации данной функции вначале переведем компонент memo в рисунок, затем получим высоту строки в точках. Затем множим высоту строки на количество строк - получим высоту всего текста в точках. Если высота текста превышает высоту компонента, то отображается полоса прокрутки. В противном случае полоса прокрутки исчезает.
В событии OnChange поля введите код:
procedure TForm1.Memo1Change(Sender: TObject);
var
//переменная для создания класса работы с изображением
cnv:TCanvas;
//переменная для хранения высоты текста в точках
row:integer;
begin
//создаем экземпляр класса для изображения
cnv := TCanvas.Create;
try
//привязываем ссылку экземпляра класса к ссылке поля Memo1
cnv.Handle:=GetDC(Memo1.Handle);
//устанавливаем на изображении шрифт, аналогичный полю Memo1
cnv.Font.Assign(Memo1.Font);
//в переменную записываем высоту строки текста в точках
row:=cnv.TextHeight(Memo1.Text);
except end;
//если высота строки * количество строк + 1
//больше высоты компонента
if (row*(Memo1.Lines.Count+1))>=Memo1.Height then
begin
//отображаем вертикальную полосу прокрутки
Memo1.ScrollBars:=ssVertical ;
//ставим курсор в текущую позицию
Memo1.SelLength:=0;
end
//иначе - скрываем полосу прокрутки
else
Memo1.ScrollBars:=ssNone;
//удаляем из памяти экземпляр класса
FreeAndNil(cnv);
end;
Кнопка "Рассчитать" выводит в поле Memo таблицу значений функции y=sin4x на отрезке [a,b] с заданным шагом. При этом проверяются ситуации, чтобы начало отрезка не превышало конец отрезка, чтобы шаг не был равен 0.
При выдачи таблицы значений функции нужно выдать заголовок, шапку таблицы, а потом значение.
При выдачи таблицы может возникать ситуация, когда в поле Memo может находиться текст с результатами предыдущего расчета. В этом случае нужно выдавать запрос на перезапись значений или добавление новых значений в конец поля.
Указания: нанесите на форму кнопку Button (Standard) и задайте свойство Caption=Рассчитать.
Для выполнения расчетов в событии OnClick кнопки напишем код:
procedure TForm1.Button1Click(Sender: TObject);
//описываем переменные для концов отрезка и шага
var a,b,h:real;
//описываем переменную для цикла
x:real;
begin
//конвертируем содержимое полей в числа
a:=StrToFloat(Edit1.Text);
b:=StrToFloat(Edit2.Text);
h:=StrToFloat(Edit3.Text);
//проверяем, чтобы начало отрезка не превышало его конца
//если начало больше конца
if a>b then
begin
//то выдаем сообщение об ошибке ввода
Application.MessageBox('Начало отрезка не может быть больше конца отрезка',
'Ошибка ввода',
MB_OK+MB_IconStop);
//ставим курсор
в поле для ввода начала отрезка
Edit1.SetFocus;
//завершаем работу процедуры
Exit;
end;
//проверяем значение шага
//если шаг равен 0
if h=0 then
begin
//то выдаем сообщение
Application.MessageBox('Шаг должен быть больше 0',
'Ошибка ввода',
MB_OK+MB_IconStop);
//ставим курсор в поле для шага
Edit3.SetFocus;
//завершаем работу процедуры
Exit;
end;
//проверяем, есть ли текст в поле
if Memo1.Text<>'' then
//если
текст есть, то выдаем запрос на очистку поля
if
Application.MessageBox('Очистить
поле результата?',
'Запрос',
MB_YESNO+MB_IconQuestion)=IDYES then
//если пользователь подтвердил очистку, то очищаем поле
Memo1.Clear;
//
в поле
Memo
формируем начальный заголовок
Memo1.Lines.Add('Табулирование
функции');
Memo1.Lines.Add('======================');
Memo1.Lines.Add(' x y ');
Memo1.Lines.Add('======================');
//запускаем цикл для вывода таблицы значения функции
x:=a;
while x<=b do
begin
//выдаем строку таблицы
//аргумент x выдаем с точностью 4:1
//функцию y (sin(4*x) выдаем с точностью 13:3
Memo1.Lines.Add(Format('%7.1f%11.3f',[x,sin(4*x)]));
//наращиваем счетчик цикла на величину шага
x:=x+h;
end;
// в поле Memo завершаем таблицу линией
Memo1.Lines.Add('======================');
//разблокируем кнопки
Button2.Enabled:=true;
Button3.Enabled:=true;
Button4.Enabled:=true;
end;
Кнопка "Сохранить" позволяет сохранить в указанный файл содержимое поля Memo. При этом появляется окно диалога для выбора имени файла. В диалоге можно выбрать текстовый файл. Если указанный при сохранении файл уже существует на диске, то нужно выдать запрос на перезапись файла или добавление в него новой информации.
Указания: нанесите на форму нанесите компонент SaveDialog (Dialogs) и задайте свойства: Filter='Текстовые файлы | *.*', DefaultExt=true.
На форму нанесите кнопку Button (Standard) и задайте свойства: Caption= Сохранить, Enabled=False. Для кнопки напишем код:
procedure TForm1.Button2Click(Sender: TObject);
//описываем переменные для работы с файлом и счетчик цикла
var t:TStringList;
i:integer;
begin
//выдаем на экран диалог сохранения файла
//если пользователь нажал на кнопку Сохранить
if SaveDialog1.Execute then
//если указанный файл уже существует
if FileExists(SaveDialog1.FileName then
begin
//выдаем запрос на добавление данных в файл
if Application.MessageBox('Указанный файл существует. Добавить в него данные?',
'Подтвердите',
MB_YESNO+MB_IconQuestion)=IDYES then
//если пользователь подтвердил добавление данных
begin
//создаем экземпляр класса для работы с файлом
t:=TStringList.Create;
//загружаем в класс файл
t.LoadFromFile(SaveDialog1.FileName);
//в цикле дописываем содержимое поля Memo в класс
for i:=0 to Memo1.Lines.Count-1 do
t.Add(Memo1.Lines.Strings[i]);
//сохраняем содержимое класса в файл
t.SaveToFile(SaveDialog1.FileName);
//удаляем экземпляр класса из памяти
t.Free;
end;
end
//иначе, если пользователь не согласился добавлять данные
else
//сохраняем содержимое поля Memo, перезаписывая файл
Memo1.Lines.SaveToFile(SaveDialog1.FileName);
//ставим отметку, что поле Memo не нужно сохранять
Memo1.Modified:=false;
end;
Кнопка "Экспорт" позволяет сохранить в указанный файл содержимое поля Memo. При этом содержимое поля построчно форматируется в HTML и записывается в файл. Имя файла задается с помощью диалога сохранения файла.
Указания: на форму нанесите второй компонент SaveDialog (Dialogs) и задайте свойства: Filter='HTML файлы | *.htm', DefaultExt=htm.
На форму нанесите кнопку Button (Standard) и задайте свойства: Caption=Экспорт, Enabled=false. Для кнопки напишем код:
procedure TForml.Button3Click(Sender: TObject);
// описываем пременные для работы с файлом
//и счетчик цикла
var t:TStringList; i:integer;
begin
//если в диалоге не выбран файл для сохранения
if not SaveDialog2.Execute then
//завершаем работу
Exit;
//создаем экземпляр класса для формирования класса
t:=TStringList.Create;
//сначала формируем заголовок HTML файла
t.Add('<head>');
t.Add (' <title>Табулирование функции</title>') ;
t.Add<'</head>'>;
//начинаем основную часть HTML документа
t.Add('<body>');
//выводим по центру заголовок таблицы
t.Add('<h3 аlign="center">Табулирование функции</hЗ>');
//создаем таблицу с шириной 30% и выравниваем по центру
t.Add('<table border="l" align="center" width="30%"');
//выводим шапку таблицы со столбцами шириной по 50%
t.Add('<tr>');
t.Add('<td align="center" width="50%">x</td>');
t.Add('<td align="center">y(x)</td>');
t.Add('<tr>');
//в цикле формируем текст HTML
//и дописываем в класс
for i:=4 to Memol.Lines.Count-2 do
begin
//находим в строке Memo номер символа "|"
p:=pos('|',memo1.lines[і]);
//в HTML таблице создаем новую строку
t.Add('<tr>') ;
//в первую колонку выдаем текст начиная с 1-го символа до 7-го
t.Add('<td align="center">'+Copy(Memo1.Lines[i],1,7)+'</td>')/
//во вторую колонку выводим текст начиная с 8-го символа и до конца строки
t.Add('<td align="center">'+Copy(Memo1.Lines[i],8,Length(Memo1.Lines[i])-7)+'</td>')
//закрываем строку HTML таблицы
t.Add<'</tr>');
end;
//закрываем тег таблицы
t.Add('</table>');
//закрываем тег тела HTML файла
t.Add('</body>'>;
//сохраняем содержимое класса в файл
t.SaveToFile(SaveDialog2.FileName);
//удаляем экземпляр класса из памяти
t.Free;
end;
Кнопка "Очистить" очищает поле Memo.
Указания: нанесите компонент Button (Standard) и задайте свойства: Caption=Очистить, Enabled=False. Для кнопки напишем код:
procedure TForm1.Button4Click(Sender: TObject);
begin
//выдаем запрос на выполнение операции
if Application.MessageBox('Очистить поле результата?',
'Подтвердите',
MB_YESNO+MB_IconQuestion)=IDYES then
begin
//если пользователь ответил "да"
//очищаем поле
Memo1.Clear;
//ставим курсор в поле для ввода начала отрезка
Edit1.SetFocus;
//блокируем кнопки
Button2.Enabled:=false;
Button3.Enabled:=false;
Button4.Enabled:=false;
//ставим отметку, что поле Memo не нужно сохранять
Memo1.Modified:=false;
end;
end;
Если пользователь рассчитает таблицу значений функции и без сохранения результата попробует выйти из программы, то нужно выдать сообщение о необходимости сохранения данных и обработать ответ пользователя.
Указания: для формы в событии OnClose напишем код:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//если содержимое поля Memo не сохранялось
if Memo1.Modified then
//выдаем запрос на сохранение данных в файл
if Application.MessageBox('Результат не сохранен. Сохранить?',
'Подтвердите',
MB_YESNO+MB_IconQuestion)=IDYES then
//если пользователь подтвердил сохранение
//вызываем процедуру для кнопки "Сохранить"
Button2Click(Sender);
end;