Практическое занятие № 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;