Программирование на Lazarus

Тип TStringList. Работа с папками

Показывать лекцию целиком

Цель лекции

Научиться использовать тип TStringList, освоить различную работу с папками.

TStringList

До сих пор мы с вами работали с файлами только с помощью компонентов, например, TMemo. Однако для этого есть и другие способы, и самый простой - тип данных TStringList. TStringList является потомком класса TStrings, который нам уже встречался - свойство Lines у TMemo, и свойство Items у компонентов TListBox и TComboBox. Напрямую работать с типом TStrings нельзя, а вот с TStringList можно.

TStringList позволяет создавать текстовые файлы, записывать в них текст или наоборот, считывать его из файла, добавлять строки и совершать с текстом массу других полезных действий. В переменной типа TStringList данные хранятся в виде отдельных строк, и можно обратиться либо ко всему тексту целиком, либо к одной из его строк. Чтобы использовать этот тип данных, мало объявить переменную типа TStringList, нужно еще эту переменную проинициализировать (создать), а после работы с ней - уничтожить. Делается это следующим образом:

var
  sl: TStringList;  //объявили переменную
begin
  sl:= TStringList.Create;  //проинициализировали
  … ;  //какие-то действия с переменной
  sl.Free;  //уничтожили
    

Когда мы только объявили переменную, компилятор еще не выделил под нее память. А вот когда мы вызвали метод Create, то в ОЗУ для переменной sl была выделена память. Сама переменная типа TStringList является указателем - она указывает на текст, хранящийся в памяти, а также количество занимаемых текстом байт. После инициализации переменной можно пользоваться: создавать с ее помощью файлы, обрабатывать текст и так далее. А вот когда мы вызываем метод Free, мы освобождаем память, занимаемую переменной, уничтожаем ее. После этого с переменной работать уже нельзя, попытка обращения к ней вызовет ошибку.

Попробуем использовать этот тип на практике. Откройте Lazarus с новым проектом. Сразу же сохраните его в папку 22-01, переименовывать форму и проект не будем, оставим имена по умолчанию.

В свойстве Caption формы напишите Использование TStringList. Добавьте на форму один компонент TEdit и четыре простых кнопки TButton. У TEdit очистите свойство Text, а в свойствах Caption кнопок напишите, соответственно:

Добавить строку в текст
Вывести текст на экран
Сохранить в файл
Читать из файла
    

В результате у вас должна получиться примерно такая форма:

(рис 22.1) Форма программы

Чтобы с переменной можно было работать отовсюду, объявим её, как глобальную, над служебным словом implementation:

(рис 22.2) Объявление глобальной переменной

Поскольку переменная глобальная, то выделять под нее память нужно сразу, до нажатий на кнопки. В подобных случаях для подготовительных операций, таких как инициализация глобальных переменных, например, лучше всего подходит событие формы OnCreate. А для освобождения памяти перед закрытием программы лучше всего использовать свойство формы OnClose. Выделите форму, перейдите на вкладку События Инспектора объектов, и дважды щелкните по событию OnCreate, генерируя код для него. Код события очень простой:

procedure TForm1.FormCreate(Sender: TObject);
begin
  //инициализируем переменную:
  sl:= TStringList.Create;
end;
    

Здесь мы просто выделили память для глобальной переменной, и сделали это сразу в начале работы программы, еще до показа формы на экране. Код события OnClose не сложнее:

procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  //уничтожаем переменную:
  sl.Free;
end;
    

Таким образом, мы гарантировали выделение и освобождение памяти для переменной. Теперь с переменной sl можно будет работать в любой процедуре или функции программы. Код обработки первой кнопки будет таким:

procedure TForm1.Button1Click(Sender: TObject);
begin
  //если текста нет, сразу выходим:
  if Edit1.Text = '' then exit;
  //добавляем строку в конец текста:
  sl.Add(Edit1.Text);
  //очищаем Edit1:
  Edit1.Text:= '';
end;
    

Как видите, вначале мы сделали проверку - есть ли текст в строке Edit1? Если текста нет, то мы выходим из процедуры, ничего не делая. Если текст существует, то вначале мы добавляем его в переменную sl, а затем очищаем Edit1 для нового текста.

Код обработки второй кнопки еще проще:

procedure TForm1.Button2Click(Sender: TObject);
begin
  ShowMessage(sl.Text); //выводим весь текст на экран
end;
    

Здесь нам не нужно делать проверку на существование текста - даже если текста нет, будет выведено пустое сообщение. Если текст есть, он будет выведен на экран. Код для третьей кнопки:

procedure TForm1.Button3Click(Sender: TObject);
begin
  //сохраняем текст в файл:
  sl.SaveToFile('mytext.txt');
end;
    

Тут, я думаю, все понятно - таким же образом мы сохраняли текст в файл с помощью компонента TMemo. Если файла нет, он будет создан, если есть - перезаписан. Обратите внимание, мы указали просто имя файла. То есть, файл будет создан в текущей папке - папке с программой. Если вы хотите, чтобы файл сохранялся где-то в конкретном месте, то вместе с именем нужно указывать и адрес, например:

  sl.SaveToFile('C:/mytext.txt');
    

Код чтения из файла для последней кнопки чуть сложнее, поскольку нам еще нужно проверить существование файла:

procedure TForm1.Button4Click(Sender: TObject);
begin
  //читаем текст из файла, если он существует:
  if FileExists('mytext.txt') then
    sl.LoadFromFile('mytext.txt');
end;
    

Функция FileExists возвращает True, если указанный файл существует. В этом случае будет выполнено чтение из файла. Если бы такой проверки не было, то попытка обращения к несуществующему файлу привела бы к ошибке программы. Если при сохранении вы указывали имя файла вместе с его адресом, тут также придется указать адрес. Попробуйте работу программы, поэкспериментируйте с кнопками, убедитесь, что файл создается.

Однако, это еще не все. Фактически, переменная типа TStringList является массивом строк, из которых состоит текст. Как уже говорилось выше, обратиться можно не только ко всему тексту, но и к его конкретной строке, указав её индекс. Индексация строк начинается с нуля, свойство переменной Count содержит общее количество строк. Исправим код для кнопки "Вывести текст на экран" - выведем не весь текст, а только его последнюю строку:

procedure TForm1.Button2Click(Sender: TObject);
begin
  //если вообще текст есть:
  if sl.Count > 0 then
    //то выведем на экран последнюю строку:
    ShowMessage(sl[sl.Count - 1]);
end;
    

Как видите, теперь нам пришлось сделать проверку - а есть ли текст? Если текста нет, то попытка обращения к несуществующей строке вызовет ошибку программы. Поскольку индексация строк начинается с нуля, то индекс последней строки будет Count минус единица. Тут вы можете заметить разницу обращения к тексту. Весь текст содержится в:

sl.Text
    

А первая строка это:

sl[0]
    

Кроме Count, тип TStringList имеет и другие, известные по TMemo инструменты-методы:

Add - добавить новую строку в конец текста, например:

sl.Add('Новая строка');
    

Clear - очистить текст, например:

sl.Clear;
    

Insert - вставить строку в конкретное место, указав индекс строки. Например, вставить вторую строку:

sl.Insert(1, 'Новая вторая строка');
    

Delete - удалить указанную строку. В метод передается индекс удаляемой строки. Например, удалить последнюю строку:

sl.Delete(sl.Count - 1);
    

Работа с папками

В Lazarus имеется несколько полезных функций и процедур для различной работы с папками (каталогами), которые вы можете применять в своих программах. Изучим их. При желании, можете создать простое приложение с единственной кнопкой TButton на форме. Сгенерируйте процедуру OnClick для неё, и в этой процедуре поочередно можете проверять рассмотренные далее примеры.

GetCurrentDir - функция возвращает адрес и имя текущей папки. Функция описана в модуле SysUtils, то есть, чтобы использовать функцию, нужно убедиться, что SysUtils подключен в разделе uses. Пример использования:

  ShowMessage(GetCurrentDir);
    

GetDir - функция возвращает текущую папку на указанном в параметре диске. Имеется два параметра: номер диска (целое число) и имя текстовой переменной, куда будет записан результат работы функции. Имейте в виду, что нумерация дисков начинается с 1, это будет диск A:. Первый жесткий диск C: имеет номер 3. Если указать номер диска 0, то будет выводится информация о текущей папке текущего диска. В Linux и других Unix-подобных системах нумерация диска игнорируется. Функция описана в модулях System и SysUtils, для использования будет достаточно, если подключен один из них. Пример использования:

procedure TForm1.Button1Click(Sender: TObject);
var
  s: string;
begin
  GetDir(3, s);  //в переменную s получили текущую папку на диске C:
  ShowMessage('Текущая папка на диске C: - ' + s);
end;
    

DirectoryExists - функция проверяет, существует ли указанная в параметре папка. Если папка существует, функция возвращает True, если нет - False. Если адрес папки не указан, то делается проверка на существование папки внутри текущей папки. Функция описана в модуле SysUtils, её следует использовать, если программа будет обращаться к какой-то папке: копировать её или просто сделать текущей. Если папки нет - это вызовет ошибку программы, поэтому проверка на существование в таких случаях обязательна. Пример использования:

  if not DirectoryExists('C:\Temp') then  ShowMessage('Папки "C:\Temp" не существует')
  else ShowMessage('Папка"C:\Temp" существует!!!');
    

ChDir - процедура, делает текущей указанную в параметре папку. Процедура описана в модулях System и SysUtils, чтобы её использовать, достаточно подключить один из них. Пример использования:

  ChDir('C:\Temp\111');  //изменили текущую папку
  ShowMessage('Теперь текущая папка: ' + GetCurrentDir);
    

SetCurrentDir - функция, делает указанную в параметре папку текущей и возвращает True в случае успеха, или False, если произошла ошибка (например, указанной папки не существует). Функция описана в модуле SysUtils. Пример использования:

  if SetCurrentDir('C:\Temp\1111') then  ShowMessage('Сменили текущую папку')
  else ShowMessage('Ошибка! Сменить папку не удалось');
    

CreateDir - функция, создает указанную в параметре папку. В случае успеха возвращает True, в случае неудачи - False. Неудача может случиться, если отсутствуют права на создание папки, например, диск доступен только для чтения, или такая папка уже существует. Функция описана в модуле SysUtils. Следующий пример будет успешным при первом обращении (если конечно, папку вообще можно создать), и неуспешном при последующих, так как такая папка уже будет:

  if CreateDir('C:\Temp\MyNewDir') then
    ShowMessage('Создали новую папку')
  else ShowMessage('Ошибка! Создать папку не удалось');
    

ForceDirectories - функция, создает указанную папку и все недостающие папки. В случае успеха возвращает True, в случае неудачи - False. Функция описана в модуле SysUtils. В следующем примере на диске C: будет создана папка MyNewDir, а в ней - папка 123:

  if ForceDirectories('C:\MyNewDir\123') then ShowMessage('Папки созданы')
  else ShowMessage('Ошибка создания папок');
    

RemoveDir - функция, удаляет указанную в параметре папку. Чтобы удаление было успешным, папка должна быть пустой. Если в параметре указан не абсолютный путь (вместе с адресом), функция пытается удалить указанную папку внутри текущей папки. В случае успеха возвращает True, в случае неудачи - False. Функция описана в модуле SysUtils. Пример использования:

  if RemoveDir('C:\MyNewDir\123') then ShowMessage('Папка удалена')
  else ShowMessage('Ошибка удаления папки');
    

RmDir - процедура, удаляет указанную в параметре папку. В отличие от RemoveDir, не возвращает никаких значений и не может удалить текущую папку. При попытке удалить несуществующую папку вызывает ошибку программы, так что применять нужно только совместно с DirectoryExists, во избежание неприятных ошибок. А лучше всегда пользоваться RemoveDir. Пример использования:

  RmDir('C:\MyNewDir\123');
    
Вернуться к учебному плану