MkDir — Процедура Delphi


Содержание

MkDir — Процедура Delphi

Для начала начнем с простой функции для создания новой папки. Общий вид функции такой:

function CreateDir(const Dir: string): Boolean;

То есть если папка успешно создана функция возвращает true . Сразу же простой пример ее использования:

procedure TForm1.Button1Click(Sender: TObject);
begin
if createdir(‘c:\TestDir’) = true then
showmessage(‘Директория успешно создана’)
else
showmessage(‘При создании директории произошла ошибка’);
end;

При нажатии на кнопку программа пытается создать папку с именем TestDir на диске C: и если попытка увенчалась успехом, то выводится соответствующее сообщение. Следует отметить, что если вы не указываете имя диска, на котором хотите создавать папку, то функция будет создавать папку в той же директории, где находится сама программа.

приведут к одному и тому же результату.

Теперь рассмотрим функцию для удаления папок. Ее объявление выглядит так:

function RemoveDir(const Dir: string): Boolean;

Сразу же хочу предупредить, что данная функция способна удалять только пустые папки, и если там что-нибудь будет, то произойдет ошибка! Но выход есть. Здесь нам на помощь придет пользовательская функция с простым названием MyRemoveDir. Вот описание функции:

Function MyRemoveDir(sDir : String) : Boolean;
var
iIndex : Integer;
SearchRec : TSearchRec;
sFileName : String;
begin
Result := False;
sDir := sDir + ‘\*.*’;
iIndex := FindFirst(sDir, faAnyFile, SearchRec);

while iIndex = 0 do begin
sFileName := ExtractFileDir(sDir)+’\’+SearchRec.Name;
if SearchRec.Attr = faDirectory then begin
if (SearchRec.Name <> » ) and
(SearchRec.Name <> ‘.’) and
(SearchRec.Name <> ‘..’) then
MyRemoveDir(sFileName);
end else begin
if SearchRec.Attr <> faArchive then
FileSetAttr(sFileName, faArchive);
if NOT DeleteFile(sFileName) then
ShowMessage(‘Could NOT delete ‘ + sFileName);
end;
iIndex := FindNext(SearchRec);
end;

RemoveDir(ExtractFileDir(sDir));
Result := True
end;

Копируете это все в Вашу программу, а затем эту функцию можно вызвать например так:

if NOT MyRemoveDir(‘C:\TestDir’) then
ShowMessage(‘Не могу удалить эту директорию’);

Теперь маленько отстранимся от непосредственной работы с папками и рассмотрим волнующий многих вопрос. Как вызвать диалог выбора папки (как при установке программ)?? ПРОСТО.

Подключаем в uses модуль Filectrl.pas (то есть uses FileCtrl;). Теперь ставим на форму еще кнопочку (чтобы не путаться :) и пишем такой код:

procedure TForm1.Button3Click(Sender: TObject);
const
SELDIRHELP = 1000;
var
Dir: string;
begin
Dir := ‘C:\windows’;
if SelectDirectory(Dir, [sdAllowCreate, sdPerformCreate, sdPrompt],SELDIRHELP) then
Caption := Dir;
end;

При выборе директории в заголовке формы отобразиться ее название!

Теперь рассмотрим следующую процедуру. К примеру Вам надо создать папку Dir1 по адресу: C:\MyDir\Test\Dir1, но при этом папок MyDir и Test на Вашем компьютере не существует. Функция CreateDir здесь не сработает, поэтому воспользуемся процедурой ForceDirectories. Ее общий вид таков:

procedure ForceDirectories(Dir: string);

Пример ее использования (как всегда я поставил на форму новую кнопку, а там написал)

procedure TForm1.Button4Click(Sender: TObject);
var
Dir: string;
begin
Dir := ‘C:\MyDir\Test\Dir1’;
ForceDirectories(Dir);
end;

Ну и напоследок приведу функцию для проверки: существует ли директория или нет. Ее общий вид такой:

function DirectoryExists(Name: string): Boolean;

Если директория указанная в параметре Name существует — то функция возвратит true.

Надеюсь, что помог Вам описанием данных функций и процедур. Сразу хочется дать совет: почаще заглядывайте в HELP, там много интересной и полезной информации!

Процедуры Delphi

В процессе программирования на языке Delphi, как и на любом другом языке программирования, основная задача программиста состоит в том, чтобы разработать процедуры (подпрограммы) для обработки определенных событий. Как только это событие возникло, проводится автозапуск процедуры обработки события (если возникло соответствующее событие, Delphi осуществляет вызов процедуры обработки возникшего события). Именно эту процедуру разработчик программы и должен описать.

Главное отличие процедуры от функции состоит в том, что есть связь между именем функции и значением. Таким образом, возможно использование имени функции в разнообразных выражениях. Организация процедуры Delphi по сути ничем не отличается от организации функции.

Как и для функции, в начале каждой процедуры указывают ее заголовок. Затем называют эту процедуру каким-нибудь именем. После имени в скобках следует перечень параметров, заканчивающийся символом «;» и потом уже описывают разделы констант, типов, переменных и инструкций.

Общий вид процедуры Delphi:

Общий вид процедуры Delphi выглядит следующим образом:

В приведенном выше примере, как мы видим, в состав заголовка процедуры сначала входит служебное словоprocedure. Далее за этим ключевым словом следом располагается имя процедуры, использующееся при вызове процедуры, обеспечивая активизацию ее выполнения.

Если процедура обладает какими-либо параметрами, то программист их указывает в скобках, сразу после имени процедуры. В конце заголовка процедуры ставится символ «;». В случае, когда в процедуре имеются именованные константы, программист объявляет их в разделеconst.

Далее за этим разделом идет раздел type, использующийся для объявления типов. После располагается раздел var, содержащий все переменные, которые впоследствии программист использует в своей программе. Затем следует раздел инструкций , которые включает в себя исполняемые инструкции данной процедуры.

Примеры процедуры Delphi:

Приведем пример процедуры Delphi, вычисляющей стоимость некоторой покупки:

Delphi-Help

Урок 25. Работа с файлами и каталогами (часть 1)

  • размер шрифта уменьшить размер шрифтаувеличить размер шрифта
  • Печать

Работа с файлами и каталогами (часть 1)

Введение

Несмотря на то, что предыдущий урок был посвящён записям, но тема не была раскрыта полностью, данный урок будет о другом — о том, как работать с файлами и с каталогами. Эти знания нам понадобятся в дальнейшем при работе с записями, поэтому логично рассказать об этом прямо сейчас. Кроме того, вопросы относительно файлов и папок возникают достаточно часто.

Вспомним, о чём, собственно, речь.

Для обычного пользователя, который не занимается программированием, знать о файлах и папках много не нужно. Достаточно иметь базовые представления, что это такое, как это используется, и какие возможны операции. Однако при программировании необходимо понимание того, что находится «внутри» и как всё это работает.
Итак, файл. Существуют сотни определений этого слова, но все они крутятся вокруг одно и того же. Файл (file) — это совокупность байтов, хранящаяся во внешней памяти и имеющая своё имя. Каждый файл мы можем найти именно по его имени. Каталог (папка, директория — folder, directory) — это своеобразный контейнер для файлов и для других папок. Каждая папка считается абсолютно «резиновой», т.е. мы можем класть в неё файлы до тех пор, пока есть место на диске: объём папки не ограничен. Эти два ключевых понятия неразрывно связаны между собой. В рамках одной папки имена файлов уникальны, т.е. не может быть двух файлов с одним именем. Следует отметить, что регистр, в котором написаны имена файлов и папок, играет свою роль. В операционной системе Windows заглавные и строчные буквы не различаются и к файлу file.txt можно запросто обратиться FILE.TXT и даже fIlE.TxT — система это прекрасно поймёт и проведёт Вас к одному и тому же файлу. Однако в некоторых других операционных системах этот принцип не работает — FILE.TXT и file.txt — два совершенно разных файла. Говорить о том, какой вариант лучше, можно долго — у каждого варианта есть свои преимущества и свои недостатки. Где ещё мы думаем или, наоборот, не задумываемся о регистре? Язык Pascal регистро-независимый: можно писать в любом регистре — как больше нравится или как удобнее. Код, написанный в любом регистре, интерпретируется совершенно одинаково. Речь не идёт, конечно, о строках и символах: при их обработке регистр, естественно, важен.
Что ещё мы должны знать? Каждый файл имеет расширение. Как правило, это 3 символа, хотя современные файловые и операционные системы позволяют делать его и большей длины. У файлов и папок есть атрибуты — некоторые свойства. Кроме того, файловая система хранит некоторую дополнительную информацию о файлах и папках — дата и время создания, открытия, изменения файла, автора и пр.
Ну что же, вроде бы основные моменты вспомнили. Теперь начнём постепенно разбираться, как же со всем этим хозяйством можно работать в Delphi.

Текстовая обработка: пути и имена файлов.

Для начала давайте узнаем, где мы вообще находимся. Я имею ввиду полный путь к исполняемому файлу нашей программы. Совершенно логично, что спрашивать нужно у самого приложения, т.е. у объекта Application. Свойство называется ExeName. Не обращайте внимания, что по названию это имя файла — вовсе нет, это самый полный путь к нему.

В качестве результата будет например следующее: C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects\Project1.exe.

Уже неплохо, согласитесь? Ориентация в пространстве — одна из важных функций. Есть и другой способ получить ту же самую информацию — функция ParamStr() с параметром 0.

Если никогда не слышали о командных параметрах — не волнуйтесь. Всему своё время. Просто используйте первый вариант. Идём дальше.

Что нам ещё нужно? Да много чего на самом деле! Например, мы хотим узнать-таки имя исполняемого файла нашей программы. Да, Вы знаете, под каким именем сохранён Ваш проект — именно так и называется исполняемый файл, но только расширение другое — exe. Однако кто сказал, что этот файл будет называться именно так всю свою жизнь? Например, в дистрибутив программа может быть включена совершенно под другим именем. Вывод: «жёстко» указывать имя в коде не пойдёт — будем брать его динамически. Откуда его можно взять? Да вот из пути, который мы только что получили! Нам поможет функция, название которой именно это и означает: «извлечь имя файла» — ExtractFileName(). Единственный параметр — путь к файлу. Итак, пробуем:

Ага, Project1.exe. Ловкость рук и никакого мошенничества. А Вы, уже было, приготовились открывать урок про работу со строками, и писать цикл по строке? :-) На самом деле, эта функция так и работает, но код уже написали давным-давно за нас.

Следующий логичный вопрос. Имя файла знаем, а как бы нам узнать только путь? Правильно, всё очень просто: «извлечь путь к файлу» — ExtractFilePath(). Параметр — снова путь:

Получили C:\Documents and Settings\ Андрей \ Мои документы \RAD Studio\Projects\. Что ещё для счастья нужно? Казалось бы, ничего? А-нет, во многих случаях в таком виде путь неприемлем. Слеш в конце лишний. Можно его удалить вручную, а можно использовать другую функцию — ExtractFileDir(). Всё то же самое, только она вернёт нам путь без слеша на конце:

Результат : C:\Documents and Settings\ Андрей \ Мои документы \RAD Studio\Projects.

У Вас наверняка есть своё рабочее место — часть комнаты дома или в офисе: стол с компьютером, кресло. Есть ещё и виртуальный рабочий стол. Программы в этом плане не обделены — у них тоже есть своё рабочее место, которое называется рабочим каталогом. Что это такое? Это та папка, которую программа считает текущей. Т.е. если никуда не ходить, то мы будем работать прямо в этой папке. Что это даёт? Это позволяет обращаться к этому уголку дискового пространства напрямую: вместо указания полного пути к файлу — только его имя. Хотим перейти в подкаталог — пожалуйста, скажите только его имя. По умолчанию рабочим каталогом программы считается тот, в котором расположен её исполняемый файл. Узнать текущий каталог можно функцией GetCurrentDir() — как всегда, логичное название («получить текущую директорию»):

В моём случае это C:\Documents and Settings\ Андрей \ Мои документы \RAD Studio\Projects. К примеру, если в этой папке создать файл new.txt, то к нему можно будет обратиться прямо new.txt, а не писать полный путь C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects\new.txt. Если есть подкаталог Data, то зайти в него — просто Data\ вместо длинного C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects\Data\. Предчувствую вопрос: а как перейти на уровень выше? Предыдущий уровень обозначается двумя точками, поэтому «..\» — это C:\Documents and Settings\Андрей\Мои документы\RAD Studio. Ну а повторив такой переход несколько раз, придём в корень диска C:. Не лишним будет также сказать, что есть и обозначение текущего каталога — одна точка («./»). Позже, когда мы попробуем получить список файлов, эти тонкости всплывут.

Ну а теперь главное. Запомните, что рабочий каталог программы вовсе не обязан быть именно в папке с exe-файлом. Этот каталог можно легко изменить — если заглянуть в свойства ярлыка к любой программе, там есть поле «Рабочая папка». Изменение этого пути приведёт к смене рабочего каталога. К чему это ведёт, надеюсь понятно: программа начнёт обращаться к несуществующим данным, сохранять всё не там, где нужно — бардак в общем. Это одна из частых ошибок, о которой забывают, а потом не могут понять, откуда столько проблем.

Как изменить рабочий каталог? Думаю, сами догадались — функцией SetCurrentDir(). Пример:

Здесь мы поднялись на три уровня вверх. Теперь наш рабочий каталог — C:\Documents and Settings\Андрей. Аналог этой функции — ChDir(). Вы всегда можете проверить свои догадки относительно того пути, куда попадёте, в любом файловом менеджере или в оболочке — в том же Проводнике. Так, например, путь C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects\..\..\RAD Studio\ вполне законный и ничем не отличается от других.

Имена файлов и папок можно обрабатывать и изменять так, как Вам требуется. Однако есть несколько полезных функций, которые сильно облегчают работу.

Функция ExtractFileExt() позволяет извлечь расширение файла. Ext — сокращение от англ. extension — расширение. Обратите внимание, что функция возвращает расширение с первым символом точкой:

Этот код выдаст «.exe».

Помимо извлечения расширения часто требуется его изменить. Например, если нужно пересохранить файл в другой формат, изменится именно его расширение, а имя останется прежним. Есть и такая функция — ChangeFileExt(). Первый параметр — строка с именем или путём к файлу, второй — новое расширение. Пример:

В данном случае получим C:\Documents and Settings\ Андрей \ Мои документы \RAD Studio\Projects\Project1.txt.

Пожалуй, об основных моментах побеседовали. Пока что мы работали только с именами и путями. Теперь перейдём непосредственно к работе с файлами.

Есть ли, с чем работать?

Пожалуй, одно из самых частых действий — проверка, а есть ли вообще такой файл на диске? Действительно, от этого многое зависти. Если его нет, а требуется записать данные, то файл нужно создать. А если он есть, то надо решить, что делать с его прежним содержимым.

Проверка существования файла выполняется функцией FileExists() — «файл существует?». Возвращаемое значение — логическое (Boolean).

Путь к файлу может быть как абсолютным (полный путь), так и относительным (от рабочего каталога).

Как видите, всё элементарно. А как узнать, есть ли папка? Да всё то же самое, только вместо File — Directory: DirectoryExists():

Файлы и папки — понятия разные, поэтому и функии для проверки разные. Вполне может существовать папка new.txt и файл Data (без расширения).

О том, что все так любят делать.

Догадались, о чём пойдёт речь? Да-да, именно об удалении. Сломать проще, чем построить. Однако удалять ненужное — благое дело. С удалением всё не так просто, как с проверкой существования. Когда Вы пытаетесь удалить файл, какая-нибудь программа может его использовать. Естественно, файловая система удалить его не позволит.
Чтобы удалить файл, следует воспользоваться функцией DeleteFile(). Параметр — путь к файлу. Функция возвращает True, если файл успешно удалился, и False, если сделать этого не получилось.

Есть и альтернатива — процедура RmDir(), однако об успешности удаления она не сообщает.

О том, как создавать папки

Пришли к главному — как создавать папки и файлы, как записывать в них информацию и читать её оттуда.

Начнём с того, как создавать папки. Здесь всё достаточно просто. Создать папку позволяет функция CreateDir() и процедура MkDir(). Аналогично удалению, первая может сказать о том, получилось ли создать, а вторая лишь молча попробует сделать своё дело.

Есть и более интересная модификация — функция ForceDirectories(). Она позволяет создать сразу целую цепочку вложенных друг в друга папок. Например, мы хотим создать папку Files, в ней Documents, а в последней — Срочное. Вариант с использованием MkDir():

Неудобно, согласитесь? И это только 3 папки. А бывают случаи, когда нужны цепочки и длиннее. Функция ForceDirectories() автоматически создаёт всё недостающее по указанному пути. Одна особенность — функция требует на вход полного (абсолютного) пути. Для нашего примера:

В этом случае получаем C:\Documents and Settings\ Андрей \ Мои документы \RAD Studio\Projects\Files\Documents\ Срочное .

О том, как создавать файлы и работать с их содержимым.

С файлами не всё так просто, как с папками. Это очевидно хотя бы из того, что папка — это просто оболочка с именем. У файла же есть ещё и содержимое. Прежде чем рассказать о механизме работы с файлами, нужно ввести одно важное понятие.

Под указателем в программирование понимается некоторая ссылка, которая может однозначно привести нас к какому-либо объекту. Указатели бывают разные. Например, указатель на ячейку памяти, в которой хранятся какие-либо данные. В этом случае указатель хранит адрес этой ячейки. Указатели существуют во многих операциях, без них доступ к данным невозможен. В реальной жизни указатель можно сравнить с адресом дома, с номером комнаты. Если нам известно, куда идти, то мы туда придём и сделаем то, что нужно. Если указатель (адрес) потерян, найти место проблематично, а то и вовсе невозможно. При работе с файлами тоже используются своего рода указатели. Дело в том, что работа с файлом делится на несколько этапов. Сначала файл нужно открыть. Без этого нельзя ни прочитать из него данные, ни записать их в него. Когда файл открыт, с его содержимым можно выполнять требуемые действия. По окочании работы файл нужно закрыть. Железное правило: не забывайте закрывать открытые файлы! Весь процесс можно увидеть и в реальной жизни: открыл дверь, зашёл, что-то сделал, вышел, закрыл дверь. Если файл не закрыть, можно его заблокировать: система будет думать, что он занят программой, однако программа уже завершила работу и потеряла указатель на него. Результат: открыть файл уже не получится. Лечится такая ситуация либо перезагрузкой системы, либо использованием специальных программ типа File Unlocker, которые восстанавливают доступ к занятым файлам. А теперь начнём разбираться, как работать с файлами.

1. Объявление указателя.

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

В качестве типа данных задаётся тот тип, переменную которого можно считать одной записью в файле. Это означает, что Вы изначально подразумеваете файл разбитым на некоторое количество записей. Именно с каждой такой записью будут выполняться все операции: добавление записи в файл или удаление записи из него. Обычный текстовый файл — это набор байтов: каждый символ кодируется один байтом (не принимая в расчёт файлы, содержащие текст в формате Юникода), поэтому текстовый файл описывается так:

Вместо Byte можно написать Char. С последним работать удобнее, если в файле записан текст. Поскольку чаще всего приходится работать именно с текстовыми файлами, был введён отдельный тип

Указатели чаще всего называют буквой F (file).

Итак, указатель есть. Переходим к следующему шагу.

2. Установка связи с файлом.

Этот этап можно сравнить с поиском двери нужного Вам номера. Связь устанавливается процедурой AssignFile():

Первый параметр — указатель, который мы объявили в п.1. Путь к файлу может как абсолютным, так и относительным.

После этой операции мы готовы к открытию файла.

3. Открытие файла.

Открытие — не такая простая операция. Она может выполняться в трёх разных режимах.

Rewrite — перезапись файла (в т.ч. создание несуществующего файла). Подразумевает очистку содержимого файла и установку текущей позиции (её тоже называют указателем) в начало файла.

Reset — открытие файла только для чтения. Указатель устанавливается в начало файла.

Append — добавление. Используется для записи данных в конец файла, не затрагивая существующие данные. Указатель ставится в конец.

Что за указатель тут используется? Это не тот, который даёт нам доступ к файлу. Представьте внутреннее содержимое файла как текст. В текстовом редакторе есть курсор, который находится в какой-то конкретной позиции. С файлом то же самое: есть невидимый курсор, посредством которого можно работать с содержимым. Если требуется записать данные в файл, курсор ставится в нужную позицию и далее выполняется запись. Если нужно прочитать — перемещаемся в нужное место и, шаг за шагом, считываем нужные данные. Указатель при этом каждый раз движется вперёд. Рано или поздно он достигнет конца файла.

Функции вроде OpenFile нет — вместо неё есть 3 функции с названиями, приведёнными выше: Rewrite(), Reset(), Append(). Единственный обязательный параметр всех этих функций — указатель на наш файл, причём тот, с помощью которого уже установлена связь с помощью AssignFile().

4. Закрытие файла.

Закрытие выполняется помощью CloseFile() передачей переменной-указателя на файл.

Вот и основные сведения о том, как работать с файлами. При работе следует заботиться обо всём, что может произойти. Так, например, если попытаться открыть файл для чтения функцией Reset(), которого не существует, произойдёт ошибка.

Пример 1. Создадим пустой текстовый файл.

Мы объявили переменную F типа «текстовый файл», далее привязали её к файлу new.txt, сделали перезапись файла и закрыли его. В итоге получен пустой файл.

Набор из трёх команд необходимо выполнять при работе с любым файлом.

Чтение и запись

Для чтения и записи существуют процедуры с понятными именами Read() и Write(). Процедуры необычые: у них неограниченное число параметров. У обеих первым параметров передаётся указатель на файл, а дальше — список переменных (или значений), с которыми нужно выполнить данную операцию. Команда Read() читает одну запись из файла и заносит её в переменную, которая указана вторым параметром. При этом указатель сдвигается на одну позицию. Если указать несколько переменных — в них будут считаны значения по порядку. Функция автоматически распознаёт разделители значений — пробелы, что позволяет с лёгкостью считывать несколько значений из файла. Запись работает аналогично: все переданные значения последовательно записываются в файл.

Помните, что пока Вы не закрыли файл, внесённые изменения в нём не сохраняются!

Пример 2. Запись в файл.

В данном примере показано использование Write(). В результате в файле будет строка «123 10». Были записаны как явно заданные строки, так и значения переменных.

Пример 3. Считывание из файла двух чисел.

В данном примере файл открывается для чтения (Reset) и из него считываются записанные там значения в переменные a и b. На экран будет выведено сообщение «123 ; 10».

Процедуры Read() и Write() не проверяют типов данных, которые используются при работе с файлом. Так что можно напрямую записывать числа, не преобразуя их в строки, и обратно из строк в числа при чтении.

Итак, записывать и читать данные научились. Но хватит ли этого для решения любых задач? Нет.

Гораздо чаще требуется работать с файлами построчно, т.е. считывать и записывать целые строки. Реакция функций на пробелы-разделители будет только вставлять палки в колёса. На помощь приходят функции ReadLn() и WriteLn(). Ln — сокращение от line (строка). ReadLn() читает целую строку из файла, а WriteLn() записывает данные и вставляет после них признаки конца текущей строки и начала новой. В остальном работа этих функций точно такая же.

Когда выполняется чтение файла, указазатель («курсор») перемещается автоматически. Понятно, что в какой-то момент мы придём к концу файла и дальше читать уже будет нечего. Чтобы отследить это состояние, используется функция EOF() — сокращение от end of file (конец файла). Передаём указатель на файл и узнаём, дошли ли до конца. Что может быть проще? Таким образом, чтение файла легко записывается в цикл.

Пример 4. Считывание всего файла в ListBox.

Разберём пример построчно:

Связываемся с файлом new.txt.

Открываем файл для чтения (указатель в начале файла).

До тех пор, пока не дошли до конца файла.

. читаем очередную строку в переменную S.

и добавляем эту строку в ListBox.

Механизм простой, и, надеюсь понятный.

Пример 5. Сохранение всех строк из поля Memo в текстовый файл.

Установили связь с файлом.

Проходим по всем строкам Memo1.

. и переписываем каждую строку в файл.

Считаю необходимым напомнить, что операции сохранения и загрузки из файла в Memo и ListBox предусмотрены. Эквиваленты для данных примеров:

Заключение.

Мы рассмотрели работу с файлами и каталогами. Научились работать с путями и именами файлов, а также узнали, как записывать информацию в файлы, и как считывать её оттуда. Конечно, это далеко не всё. Ещё множество вопросов осталось за кадром. Как определить объём файла? Как скопировать, переместить, переименовать файл? Речь об этом пойдёт во второй части данной темы, однако в следующем уроке мы вернёмся к работе с записями.

Процедуры и функции для работы с файлами в Delphi

Читайте также:

  1. Cущность банковского процента, его функции и роль.
  2. I. Функции времени в спутниковых технологиях.
  3. I. Экстремумы функции двух переменных
  4. II. Основные направления социально-медицинской работы с семьями детей ограниченными возможностями
  5. III. Лекционный материал по теме: ПРАВИЛА РАБОТЫ НА ЛЕКЦИИ
  6. IV. Функции
  7. IX. Лекционный материал: ОРГАНИЗАЦИЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
  8. N В условиях интенсивной мышечной работы, при гипоксии (например, интенсивный бег на 200м в течении 30 с) распад углеводов временно протекает в анаэробных условиях
  9. N Выполняет функции гормона
  10. N Особенности структуры и функции обуславливают особенности в метаболизме клеток
  11. TCR. Функции Т-лимфоцитов
  12. VIII. Принципы работы вычислительной системы

Основные процедуры и функции:

Процедура: AssignFile(var Vf; FileName: string);Модуль: System

Описание: Процедура устанавливает ассоциативную связь между файловой переменной Vf и внешним файлом, имя которого определено параметром FileName. Все операции, производимые с файловой переменной, будут производиться со связанным с ней файлом. FileName — выражение типа string или PChar (если допускается расширенный синтаксис). Если в качестве имени файла указать пустую строку, то файловая переменная будет ассоциирована со стандартным файлом ввода (когда после AssignFile следует процедура Reset) или вывода (когда после следует процедура Rewrite).

Пример:
var Vf : file of Integer;
begin
.
AssignFile(Vf,'work.dat'); //инициализирует файловую переменную
Rewrite(Vf); //создает файл 'work.dat'
CloseFile(Vf); //закрывает файл
.
end;

Процедура: BlockRead(var Vf: file; var Buf; Count: Integer [;var AmtTransferred: Integer]); Модуль: System

Описание: Процедура читает одну или большее количество записей из открытого файла, связанного с файловой переменной Vf, в переменную Buf. Параметр Count определяет количество записей, которое необходимо прочитать из файла. В параметре AmtTransferred возвращается фактическое количество прочитанных записей, которое может быть меньше Count (например, когда размер последнего блока данных в файле меньше заданного размера записи). Максимальный размер прочитанного блока равен Count*RecSize байт. RecSize — размер записи, определенный, во время открытия файла (если размер записи не был задан, то используется значение по умолчанию — 128 байт). Параметр AmtTransferred является необязательным. Но если данный параметр опущен, а количество прочитанных записей меньше Count, то возникнет ошибка ввода/вывода (исключение EInOutError).

Пример:
var
Vf1, Vf2: file; NRead, NWrite: Integer;
Buf: array[1..1024] of Char;
begin
AssignFile(Vf1, 'read.txt');
Reset(Vf1, 1); //Устан-ет размер записи входного файла = 1
AssignFile(Vf2, 'write.txt');
Rewrite(Vf2, 1); //Устан-ет размер записи выходного файла = 1
repeat
BlockRead(Vf1, Buf, SizeOf(Buf), NRead); //читает данные
BlockWrite(Vf2, Buf, NRead, NWrite); //записывает данные
until (NRead = 0) or (NWrite <> NRead);
CloseFile(Vf1);
CloseFile(Vf2);
end;

Процедура: BlockWrite(var Vf: file; var Buf, Count: Integer [;var AmtTransferred: Integer]); Модуль: System

Описание: Процедура записывает одну или несколько записей из переменной Buf во внешний файл, связанный с файловой переменной Vf. Параметр Count определяет количество записей, которое необходимо записать в файл. В параметре AmtTransferred возвращается фактическое количество скопированных записей, которое может быть меньше Count (например, когда место на диске закончилось до окончания записи в файл). Максимальный размер записываемого блока равен Count*RecSize байт, где RecSize — размер записи, определенный, во время открытия файла или 128 байт, если размер записи не был определен. Параметр AmtTransferred является необязательным. Но если данный параметр опущен, и количество прочитанных записей будет меньше Count, то возникнет ошибка ввода/вывода (исключение EinOutError).

Пример:
var
Vf1, Vf2: file;
NRead, NWrite: Integer;
Buf: array[1..1024] of Char;
begin
AssignFile(Vf1, 'read.txt');
Reset(Vf1, 1); //Устан-ет размер записи входного файла = 1
AssignFile(Vf2, 'write.txt');
Rewrite(Vf2, 1); //Устан-ет размер записи выходного файла = 1
repeat
BlockRead(Vf1, Buf, SizeOf(Buf), NRead); //читает данные
BlockWrite(Vf2, Buf, NRead, NWrite); //записывает данные
until (NRead = 0) or (NWrite <> NRead);
CloseFile(Vf1);
CloseFile(Vf2);
end;

Процедура: CloseFile(var Vf); Модуль: System

Описание: Процедура разрывает ассоциативную связь между файловой переменной и внешним файлом, при этом, файл обновляется и закрывается. Механизм обработки ошибок ввода/вывода с помощью обработчиков исключений включается директивой компилятора <$I+>. При использовании директивы <$I->информацию об ошибках можно получить с помощью функции IOResult.

Пример:
var
Vf: file of Integer;
begin
.
AssignFile(Vf, 'work.dat'); //инициализирует файловую переменную
Rewrite(Vf); //создает файл 'work.dat'
CloseFile(Vf); //закрывает файл
.
end;

Процедура: Erase(Var Vf); Модуль: System

Описание: Удаляет файл, связанный с файловой переменной Vf. Vf — файловая переменная, ассоциированная с файлом любого типа. Перед удалением файл необходимо закрыть процедурой CloseFile.

Пример:
var
Vf: file;
begin
AssignFile(Vf, 'C:\WINDOWS\TEMP\tmpfile.tmp');
Rewrite(Vf); //создает временный файл 'tmpfile.tmp'
.
CloseFile(Vf); //закрывает файл
Erase(Vf); //удаляет файл
end;

Процедура: FindClose(var F: TSearchRec); Модуль: SysUtils

Описание: Процедура завершает последовательность вызовов функций FindFirst — FindNext и высвобождает память, выделенную при вызове функции FindFirst.

Процедура: Read(Vf, V1 [, V2, . Vn ]); Модуль: System

Описание: Процедура читает информацию из файла, ассоциированного с файловой переменной Vf, в переменную(ые) Vn.

Типизированные файлы. Читает запись (компонент) из файла в переменную. Файлы строкового типа. Читает все символы до маркера конца строки, не включая его или пока значение Eof(Vf) не будет равно True. Если размер прочитанной строки больше, чем размер строковой переменной, то строка усекается. После прочтения строки, каждый последующий вызов данной процедуры будет возвращать пустую строку, т.к. процедура Read не переводит указатель на новую строку. Если необходимо прочитать более одной записи из файла, то используйте процедуру ReadLn. Файлы символьного типа. Читает символ из файла. Если достигнут конец файла (т.е. Eof(Vf)=True), то процедура возвращает символ ‘Ctrl+Z’ (ASCII код 26).

Файлы целочисленных и действительных типов. Если тип переменной соответствует формату числовой строки, то переменной присваивается прочитанное значение, иначе возникает ошибка ввода/вывода.

Пример:
var
Vf1,Vf2: TextFile;
FileName1, FileName2: string;
C: Char;
begin
FileName1:='read.txt'; //подразумевается, что файл существует
FileName2:='write.txt';
AssignFile(Vf1, FileName1);
Reset(Vf1); //открывает файл 'read.txt'
AssignFile(Vf2, FileName2);
Rewrite(Vf2); //создает файл 'write.txt'
while not Eof(Vf1) do //повтор, пока не достигнут конец файла
begin
Read(Vf1, C); //читает символ из файла 'read.txt'
Write(Vf2, C); //записывает символ в файл 'write.txt'
end;
CloseFile(Vf2);
CloseFile(Vf1);
end;

Процедура: Rename(var Vf; NewName); Модуль: System

Описание: Процедура переименовывает файл, связанный с файловой переменной Vf. Новое имя файла указывается в параметре NewName. NewName — переменная типа string или PChar (если допускается расширенный синтаксис). После выполнения данной процедуры все операции c файловой переменной Vf будут производиться над переименованным файлом.

Процедура: Reset(var Vf: File [;RecSize: Word]); Модуль: System

Описание: Процедура открывает существующий файл и устанавливает указатель в начало файла. Vf — файловая переменная, ассоциированная с файлом любого типа при помощи процедуры AssignFile. RecSize — необязательный параметр, указывающий размер записи файла. Когда параметр RecSize опущен, размер записи принимается по умолчанию 128 байт. Если файл, связанный с файловой переменной Vf, не существует, то при вызове процедуры Reset возникнет ошибка. Если файл уже открыт, то при вызове данной процедуры он сначала закрывается, а затем снова открывается. Если с файловой переменной Vf связан текстовый файл, то он открывается только для чтения.

Процедура: Rewrite(var Vf: File [; Recsize: Word]); Модуль: System

Описание: Процедура создает новый файл и открывает его. Параметр Vf определяет файловую переменную, связанную с любым типом файлов при помощи процедуры AssignFile. RecSize — необязательный параметр, указывающий размер записи файла. Когда параметр RecSize опущен, размер записи принимается по умолчанию 128 байт. Если файл с заданным именем уже существует, то процедура удаляет старый файл и создает новый пустой файл. Если файл существует и открыт, то функция перед удалением старого файла сначала закрывает его. Если файловая переменная Vf связана с текстовым файлом, то он открывается только для записи. После вызова данной процедуры Eof(Vf)=True.

Процедура: Seek(var Vf; N: Longint); Модуль: System

Описание: Устанавливает файловый указатель в заданную позицию файла. Параметр Vf представляет собой файловую переменную, ассоциированную с типизированным или нетипизированным файлом. Для успешного выполнения процедуры файл должен быть открыт. Индекс позиции, в которую будет установлен указатель, определяется параметром N. Первая позиция в файле имеет индекс 0. Если необходимо добавить данные в конец файла, то поставить указатель в конец файла Vf можно следующим образом: Seek(Vf, FileSize(Vf)).

Процедура: Truncate(var Vf); Модуль: System

Описание: Процедура удаляет все записи в файле, находящиеся после текущей позиции (текущая позиция становится концом файла). Параметр Vf представляет собой файловую переменную, связанную с файлом любого типа, кроме текстовых (данная процедура не работает с текстовыми файлами). При вызове процедуры файл должен быть открыт.

Процедура: Write(Vf, V1. Vn); (для типизированных файлов) Модуль: System

Описание: Процедура записывает данные в типизированный файл. Параметр Vf представляет собой файловую переменную, связанную с типизированным файлом. Тип переменных V1 . Vn должен соответствовать типу фала. При записи в файл очередного компонента, указатель текущей позиции файла передвигается на следующий компонент. Если перед вызовом данной процедуры указатель стоит в конце файла (Eof(Vf)=True), то записываемые данные будут добавлены в конец файла (размер файла соответственно увеличится).

Функция: DeleteFile(const FileName: string): Boolean; Модуль: SysUtils

Описание: Функция удаляет файл с диска. При успешном выполнении возвращает True, а если файл не существует, или не может быть удален, то — False.

Пример:
var
FileName: string;
begin
.
if DeleteFile(FileName) then
MessageDlg('Файла успешно удален', mtInformation, [mbOk], 0)
else
MessageDlg('Ошибка удаления файла', mtInformation, [mbOk], 0);
.
end;

Функция: DiskFree(Drive: Byte): Int64; Модуль: SysUtils

Описание: Функция возвращает количество свободного места на диске, указанном в параметре Drive, в байтах. Диск определяется следующим образом: 0 — текущий, 1 — ‘A’, 2 — ‘B’, 3 — ‘С’, и т.д. Если указанный диск не существует, или недоступен, то функция возвращает -1.

Функция: DiskSize(Drive: Byte): Int64; Модуль: SysUtils

Описание: Функция возвращает размер диска Drive в байтах. Диск определяется следующим образом: 0 — текущий, 1 — ‘A’, 2 — ‘B’, 3 — ‘С’, и т.д. Если указанный диск не существует, или недоступен, то функция возвращает -1.

Функция: Eof(var Vf ): Boolean; Модуль: System

Описание: Функция определяет, стоит ли указатель текущей позиции в конце файла Vf (Vf — файловая переменная). Если указатель стоит на последнем символе файла, или файл не содержит данных, то функция возвращает True, а иначе — False.

Пример:
var
Vf1,Vf2: TextFile;
FileName1, FileName2: string;
C: Char;
begin
FileName1:='read.txt'; //подразумевается, что файл существует
FileName2:='write.txt';
AssignFile(Vf1, FileName1);
Reset(Vf1); //открывает файл 'read.txt'
AssignFile(Vf2, FileName2);
Rewrite(Vf2); //создает файл 'write.txt'
while not Eof(Vf1) do //повтор, пока не достигнут конец файла
begin
Read(Vf1, C); //читает символ из файла 'read.txt'
Write(Vf2, C); //записывает символ в файл 'write.txt'
end;
CloseFile(Vf2);
CloseFile(Vf1);
end;

Функция: FileExists(const FileName: string): Boolean; Модуль: SysUtils

Описание: Функция проверяет, существует ли файл с именем FileName. Если файл существует, то функция возвращает True, иначе — False.

Функция: FileGetAttr(const FileName: string): Integer; Модуль: SysUtils

Описание: Функция возвращает атрибуты файла, имя которого передано в параметре FileName. Атрибуты могут быть разделены с помощью оператора AND и следующих значений констант атрибутов:

Константа Значение Описание
faReadOnly faHidden faSysFile faVolumeID faDirectory faArchive faAnyFile $00000001 $00000002 $00000004 $00000008 $00000010 $00000020 $00000003F Только чтение Скрытый файл Системный файл Идентификатор тома Каталог Архивный файл Произвольный файл

В случае возникновении ошибки функция возвращает -1.

Функция: FilePos(var Vf): LongInt; Модуль: System

Описание: Функция возвращает текущую позицию указателя в файле (файл должен быть предварительно открыт). Параметр Vf представляет собой файловую переменную, ассоциированную с файлом. Данная функция не может быть применена к текстовым файлам.

Пример:
var
Vf: File of Byte;
S : string;
Size, I: Integer;
begin
Randomize; AssignFile(Vf, 'work.dat');
Rewrite(Vf); //создает файл work.dat
for I:= 0 to 100 do
begin
Seek(Vf, I);
Write(Vf, I); //записывает в файл послед. чисел от 1 до 100
end;
Size:= FileSize(Vf); //определяет размер файла
Seek(Vf, random(Size)); //устанавливает указатель в произвольную позицию
MessageDlg('Позиция указателя: ' + IntToStr(FilePos(Vf)), mtInformation, [mbOk], 0);
.
CloseFile(Vf);
end;

Функция: FileSearch(const FileName, DirList: string): string; Модуль: SysUtils

Описание: Функция осуществляет поиск файла FileName в каталогах, указанных в параметре DirList. Имя файла должно быть представлено в DOS-формате. Список каталогов DirList представляет собой строку, содержащую наименования каталогов, разделенных точками с запятой (например, ‘C:\;C:\WINDOWS; C:\WINDOWS\TEMP’). Если файл найден, то функция возвращает полный путь к файлу, а иначе возвращается пустая строка.

Функция: FileSetAttr(const FileName: string): Integer; Модуль: SysUtils

Описание: Функция устанавливает атрибуты файла, имя которого передано в параметре FileName. Атрибуты перечисляются в параметре Attr с помощью оператора OR. В случае успешного выполнения функция возвращает 0, а иначе возвращается код ошибки Windows.
Значение констант атрибутов:

Константа Значение Описание
faReadOnly faHidden faSysFile faVolumeID faDirectory faArchive faAnyFile $00000001 $00000002 $00000004 $00000008 $00000010 $00000020 $00000003F Только чтение Скрытый файл Системный файл Идентификатор тома Каталог Архивный файл Произвольный файл

Пример:для файла устанавливаются атрибуты ‘Скрытый файл’ и ‘Только чтение’.
FileSetAttr('MyFile.zzz', faReadOnly or faHidden);

Функция: FileSize(var Vf): Integer; Модуль: System

Описание: Функция возвращает размер файла, связанного с файловой переменной Vf в байтах. Для файлов типа Record функция возвращает количество записей. Если файл не содержит данных, то функция возвращает 0. Файл должен быть обязательно открыт. Данная функция не применима к текстовым файлам.

Описание: Функция находит файл с набором атрибутов Attr в каталоге и по маске, определенных константой Path. Найденное имя файла записывается в переменную F. Если указанный файл найден, то функция возвращает 0, иначе возвращается код ошибки Windows. Параметр Attr — комбинация нескольких констант атрибутов файла или их значений. Константа Path представляет собой полный путь с маской файла (например, ‘C:\MYDIR\*.ini’ ). Повторный поиск файла производится с помощью функции FindNext. По окончанию поиска необходимо высвободить память, выделенную при вызове функции FindFirst, с помощью процедуры FindClose. Значение констант атрибутов:

Константа Значение Описание
faReadOnly faHidden faSysFile faVolumeID faDirectory faArchive faAnyFile $00000001 $00000002 $00000004 $00000008 $00000010 $00000020 $00000003F Только чтение Скрытый файл Системный файл Идентификатор тома Каталог Архивный файл Произвольный файл

Описание: Функция используется в цепочке FindFirst - FindNext - FindClose для повторного поиска файла. Первый поиск осуществляется с помощью функции FindFirst. Функция FindNext возвращает следующий найденный файл, удовлетворяющий условиям поиска определенным при вызове функции FindFirst. В случае успешного выполнения, функция FindNext возвращает 0, а в случае возникновения ошибки — код ошибки Windows. По окончанию поиска необходимо высвободить память с помощью функции FindClose.

Функция: IOResult: Integer; Модуль: System

Описание: Функция возвращает статус ошибки последней выполненной операции ввода/вывода. Использование данной функции возможно только при отключенной проверке ошибок директивой компилятора <$I->. При возникновении ошибки ввода/вывода, все последующие операции ввода/вывода будут игнорироваться до тех пор, пока не будет сделано обращение к функции IOResult. Вызов IOResult очищает внутренний флаг ошибки. Альтернативным способом обработки ошибок ввода/вывода является использование механизма обработки исключительных ситуаций, который включается директивой компилятора <$I+>.

Функция: RenameFile(const OldName, NewName: string): Boolean; Модуль: SysUtils

Описание: Функция переименовывает файл OldName в NewName. При успешном выполнении возвращает True, а в случае ошибки False.

Пример:
begin
if RenameFile('OLD.TXT', 'NEW.TXT') then
MessageDlg(Файл переименован!', mtInformation, [mbOk], 0)
else
ErrorMsg('Невозможно переименовать файл!');
end;

| следующая лекция ==>
Современные способы и средства тушения пожаров | Работа с текстовыми файлами

Дата добавления: 2014-01-07 ; Просмотров: 882 ; Нарушение авторских прав? ;

Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет

Использование процедур и функций в Delphi

Скобки

Добавление скобок при вызове процедур и функций без параметров уже давно не является новинкой в Delphi, тем не менее, эта возможность мало известна. Эту возможность оценят по достоинству те программисты, которым приходится работать на двух языках (C++ и Delphi), так как им не нужно будет постоянно помнить о разнице в синтаксисе при вызове процедур и функций в разных языках. В Delphi оба варианта, приведенные ниже, считаются корректными.

Возможность перегрузки

Впервые концепция перегрузки процедур и функций была реализована в Delphi 4. Она позволяет иметь несколько различных процедур и функций с одинаковыми именами, но с разными списками параметров. Такие процедуры и функции должны быть описаны с применением директивы overload.

procedure Test (I: integer); overload;
procedure Test (S: string); overload;
procedure Test (D: double); overload;

При вызове процедуры Test, Delphi сама решит, какую из трех процедур необходимо выполнить, в зависимости от передаваемого ей параметра. Но нужно отметить, что это не самая безопасная возможность языка. Применение перегружаемых процедур и функций может стать неиссякаемым источником трудноуловимых ошибок в программе. Поэтому пользуйтесь этой возможностью осторожно.

Передача параметров

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

Передача параметров по значению

Этот режим передачи параметров применяется по умолчанию. Если параметр передается по значению, создается локальная копия данной переменной, которая и предоставляется для обработки в процедуру или функцию. Посмотрите на следующий пример:

procedure Test(s: string);

При вызове указанной процедуры будет создана копия передаваемой ей в качестве параметра строки s, с которой и будет работать процедура Test. При этом все внесенные в строку изменения никак не отразятся на исходной переменной s.

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

Передача параметров по ссылке

Pascal позволяет также передавать параметры в функции или процедуры по ссылке — такие параметры называются параметрами-переменными. Передача параметра по ссылке означает, что функция или процедура сможет изменить полученные значения параметров. Для передачи параметров по ссылке используется ключевое слово var, помещаемое в список параметров вызываемой процедуры или функции.

procedure ChangeMe(var x: longint);
begin
x := 2; // Параметр х изменен вызванной процедурой
end;

Вместо создания копии переменной x, ключевое слово var требует передачи адреса самой переменной x, что позволяет процедуре непосредственно изменять ее значение.

Передача параметров констант

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

procedure Test(const s: string );

Передача открытых массивов

Открытый массив параметров позволяет передавать в функцию или процедуру различное количество параметров. В качестве параметров можно передать либо открытый массив элементов одинакового типа, либо массивы констант различного типа. В приведенном ниже примере объявляется функция, которой в качестве параметра должен передаваться открытый массив целых чисел.

function AddEmUp(A: array of integer): integer;

В открытом массиве можно передавать переменные, константы или выражения из констант.

Для получения информации о фактически передаваемом массиве параметров в функции или процедуре могут использоваться функции High, Low и SizeOf.

Object Pascal также поддерживает тип array of const, который позволяет передавать в одном массиве данные различных типов. Синтаксис объявления функций или процедур, использующих такой массив для получения параметров, следующий:

procedure WhatHaveIGot( A: array of const );

Вызвать объявленную выше функцию можно, например, с помощью такого оператора:

procedure WhatHaveIGot( [‘Text’, 10, 5.5, @WhatHaveIGot, 3.14, true, ‘c’] );

При передаче функции или процедуре массива констант все передаваемые параметры компилятор неявно конвертирует в тип TVarRec. Тип данных TVarRec объявлен в модуле System следующим образом:

PVarRec = ^TVarRec;
TVarRec = record
case Byte of
vtInteger: (VInteger: Integer; VType: Byte);
vtBoolean: (VBoolean: Boolean);
vtChar: (VChar: Char);
vtExtended: (VExtended: PExtended);
vtString: (VString: PShortString);
vtPointer: (VPointer: Pointer);
vtPChar: (VPChar: PChar);
vtObject: (VObject: TObject);
vtClass: (VClass: TClass);
vtWideChar: (VWideChar: WideChar);
vtPWideChar: (VPWideChar: PWideChar);
vtAnsiString: (VAnsiString: Pointer);
vtCurrency: (VCurrency: PCurrency);
vtVariant: (VVariant: PVariant);
vtInterface: (VInterface: Pointer);
vtWideString: (VWideString: Pointer);
vtInt64: (VInt64: PInt64);
end;

Поле VType определяет тип содержащихся в данном экземпляре записи TVarRec данных и может принимать одно приведенных значений.

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

procedure WhatHaveIGot( A: array of const );
var
i: integer;
TypeStr: string;
begin
for i := Low(A) to High(A) do
begin
case A[i].VType of
vtInteger : TypeStr := ‘Integer’;
vtBoolean : TypeStr := ‘Boolean’;
vtChar : TypeStr := ‘Char’;
vtExtended : TypeStr := ‘Extended’;
vtString : TypeStr := ‘String’;
vtPointer : TypeStr := ‘Pointer’;
vtPChar : TypeStr := ‘PChar’;
vtObject : TypeStr := ‘Object’;
vt ;
vtW ;
vtPW ;
vtAnsiString : TypeStr := ‘AnsiString’;
vtCurrency : TypeStr := ‘Currency’;
vtVariant : TypeStr := ‘Variant’;
vtInterface : TypeStr := ‘Interface’;
vtW ;
vtInt64 : TypeStr := ‘Int64’;
end;
ShowMessage( Format( ‘Array item %d is a %s’, [i, TypeStr] ) );
end;
end;

Значения параметров по умолчанию

В Delphi есть одна очень полезная возможность — использование значений параметров по умолчанию. Она позволяет установить принимаемое по умолчанию значение параметра процедуры или функции. Это значение будет использоваться в тех случаях, когда вызов процедуры или функции производится без указания значения данного параметра. В объявлении процедуры или функции принимаемое по умолчанию значение параметра указывается после знака равенства, следующего после его имени. Поясним это на следующем примере:

procedure HasDefVal( s: string; i: integer = 0 );

Подобное объявление означает, что процедура HasDefVal может быть вызвана двумя путями. В первом случае — как обычно, с указанием обоих параметров:

procedure HasDefVal( ‘Hello’, 26 );

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

procedure HasDefVal( ‘Hello’ );

При использовании значении параметров по умолчанию следует помнить о нескольких приведенных ниже правилах:

  • Параметры, имеющие значения по умолчанию, должны располагаться в конце списка параметров. Параметр без значения по умолчанию не должен встречаться в списке после параметра, имеющего значение по умолчанию.
  • Значения по умолчанию могут присваиваться только параметрам обычных типов, указателям или множествам.
  • Значение по умолчанию может передаваться только по значению либо с модификатором const. Оно не может быть ссылкой или нетипизированным параметром.

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

function Add( I1, I2: integer ): integer;
begin
Result := I1 + I2;
end;

Предположим также, что исследования показали целесообразность добавления в программу возможности сложения трех чисел. Однако замена имеющейся функции функцией сложения трех чисел приведет к тому, что вам придется переправлять немало текста, который перестанет компилироваться из-за внесения в функцию еще одного параметра. Однако при использовании значений параметров по умолчанию проблема решается легко и просто. Достаточно изменить объявление функции так, как показано ниже.

function Add( I1, I2: integer; I3: integer = 0 ): integer;
begin
Result := I1 + I2 + I3;
end;

Директива

Директива <$X->запрещает вызов функций как процедур (с игнорированием возвращаемого результата). По умолчанию этот режим включен (<$X+>). Так вот, запомните, использование переменной Result недопустимо при сброшенном флажке опции Extended Syntax, расположенном во вкладке Compiler диалогового окна Project Options, или при указании директивы компилятора <$X->.

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

Процедура и функция — это ключевые понятия в любом языке программирования, без которых не обходится ни одна серьезная программа. И поэтому очень важно иметь полное понимание о механизме их работы.

MkDir — Процедура Delphi

Теперь рассмотрим две самые распространенные операции, выполняемые при работе с файлами. Это чтение и запись. Для их осуществления применяются специальные функции файлового ввода/вывода.

Итак, для выполнения операции чтения или записи необходимо произвести следующие действия:

1. Объявить файловую переменную необходимого типа.

2. При помощи функции AssignFile связать эту переменную с требуемым файлом.

3. Открыть файл при помощи функций Append, Reset, Rewrite.

4. Выполнить операции чтения или записи. При этом, в зависимости от сложности задачи и структуры данных, может использоваться целый ряд вспомогательных функций.

5. Закрыть файл при помощи функции CloseFile .

По сравнению с Turbo Pascal изменились названия только двух функций: Assign стала AssignFile , a Close превратилась в CloseFile .

В качестве примера рассмотрим небольшой фрагмент исходного кода.

then AssignFiie(F, OpenDlg.FileName)

else Exit; Reset(F);

while Not EOF(F) do

Если в диалоге открытия файла OpenDlg был выбран файл, то его имя связывается с файловой переменной F при помощи процедуры AssignFiie . В качестве имени файла рекомендуется всегда передавать полное имя файла (включая его маршрут). Как раз в таком виде возвращают результат выбора файла диалоги работы с файлами TOpenDialog, TOpenPictureDiaiog . Затем при помощи процедуры Reset этот файл открывается для чтения и записи.

В цикле выполняется чтение из файла текстовых строк и запись их в компонент TMemo . Процедура Readin осуществляет чтение текущей строки файла и переходит на следующую строку. Цикл выполняется, пока функция EOF не сообщит о достижении конца файла.

После завершения чтения файл закрывается.

Такой же исходный код можно использовать и для записи данных в файл. Необходимо только заменить процедуру чтения на процедуру записи.

Теперь остановимся подробнее на назначении используемых для файлового ввода/вывода функций.

Открытие файла может осуществляться тремя процедурами — в зависимости от типа его дальнейшего использования.

procedure Reset(var F: File [; RecSize: Word ]);

открывает существующий файл для чтения и записи, текущая позиция устанавливается на первой строке файла.

открывает файл для записи информации после его последней строки, текущая позиция устанавливается на конец файла.

procedure Rewrite(var F: File [; RecSize: Word ]);

создает новый файл и открывает его, текущая позиция устанавливается в начало файла. Если файл с таким именем уже существует, то он перезаписывается.

Переменная RecSize используется только при работе с нетипизированными файлами и определяет размер одной записи для операции передачи данных. Если этот параметр опущен, то по умолчанию RecSize равно 128 байт.

Чтение данных из типизированных и текстовых файлов выполняют процедуры Read И Readin.

Процедура Read имеет различное объявление для текстовых и других типизированных файлов:

  • procedure Read([var F: Text;] VI [, V2. Vn]);
  • procedure Read(F, VI [, V2. Vn]);

для других типизированных файлов.

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

procedure Readln([ var F: Text; ] VI [, V2. Vn ]);

считывает одну строку текстового файла и устанавливает текущую позицию на следующей строке. Если использовать процедуру без переменных vi. .vn, то она просто передвигает текущую позицию на очередную строку файла.

Процедуры для записи в файл write и writein описаны аналогично:

procedure Write([var F: Text; ] PI [, P2. Pn]) ; procedure Writein([ var F: Text; ] PI [, P2. Pn ]);

Параметры P1, P2, . Pn могут быть одним из целых или вещественных типов, одним из строковых типов или логическим типом. Но у них есть возможность дополнительного форматирования при выводе. Каждый параметр записи может иметь форму:

Р n — выводимая переменная или выражение;

MinWidth — минимальная ширина поля в символах, которая должна быть больше 0;

DecPlaces — содержит количество десятичных символов после запятой при отображении вещественных чисел с фиксированной точкой.

Обратите внимание, что для текстовых файлов в функциях Read и write файловая переменная F может быть опущена. В этом случае чтение и запись осуществляются в стандартные файлы ввода/вывода. Когда программа компилируется как консольное приложение (флаг <$APPTYPE CONSOLE>), Delphi автоматически связывает входной и выходной файлы с окном консоли.

Для контроля за текущей позицией в файле применяются две основные функции. Функция EOF (F) возвращает значение True , если достигнут конец файла. Функция EOLN(F) аналогично сигнализирует о достижении конца строки. Естественно, в качестве параметра в функции необходимо передавать файловую переменную.

обеспечивает смещение текущей позиции на N элементов. Размер одного элемента в байтах зависит от типа данных файла (от типизированной переменной).

Рассмотрим теперь режим блочного ввода/вывода данных между файлом и областью адресного пространства (буфером). Этот режим отличается значительной скоростью передачи данных, причем скорость пропорциональна размеру одного передаваемого блока — чем больше блок, тем больше скорость.

Для реализации этого режима необходимо использовать только нетипизированные файловые переменные. Размер блока определяется в процедуре открытия файла ( Reset, Rewrite ). Непосредственно для выполнения операций используются процедуры BlockRead и BlockWrite .

procedure BlockRead(var F: File; var Buf; Count: Integer

[; var AmtTransferred: Integer]);

выполняет запись блока из файла в буфер. Параметр F ссылается на нетипизированную файловую переменную, связанную с нужным файлом.

Параметр Buf определяет любую переменную (число, строку, массив, структуру), в которую читаются байты из файла. Параметр Count содержит число считываемых блоков. Наконец, необязательный параметр AmtTransferred возвращает число реально считанных блоков.

При использовании блочного чтения или записи размер блока необходимо выбирать таким образом, чтобы он был кратен размеру одного значения того типа, который хранится в файле. Например, если в файле хранятся значения типа Double (8 байт), то размер блока может быть равен 8, 16, 24, 32 и т. д. Фрагмент исходного кода блочного чтения при этом выглядит следующим образом:

DoubleArray: array [0..255] of Double;

if OpenDlg.Execute then AssignFile(F, OpenDlg.FileName) else Exit;

BlockRead(F, DoubleArray, 32, Transferee!);

ShowMessage(‘Считано ‘+IntToStr(Transfered)+’ блоков’);

Как видно из примера, размер блока установлен в процедуре Reset и кратен размеру элемента массива DoubleArray , в который считываются данные. В переменной Transfered возвращается число считанных блоков. Если размер файла меньше заданного в процедуре BlockRead числа блоков, ошибка не возникает, а в переменной Transfered передается число реально считанных блоков.

procedure BlockWrite(var f: File; var Buf; Count: Integer

[; var AmtTransferred: Integer]);

Оставшиеся функции ввода/вывода, работающие с файловыми переменными, подробно описаны в табл. 9.1.

Таблица 9.1. Процедуры и функции для работы с файлом

function ChangeFileExt (const FileName, Extension: string): string;

Функция позволяет изменить расширение файла. При этом сам файл не переименовывается

procedure ChDir(S: string);

Процедура изменяет текущий каталог на другой, путь к которому описан в строке s

procedure CloseFile (var F) ;

Вызов процедуры разрывает связь между файловой переменной и файлом на диске.

Имя этой процедуры изменено из-за конфликта имен в Delphi (в Borland Pascal используется процедура Close )

function DeleteFile (const FileName: string): Boolean;

Функция производит удаление файла FileName с диска и возвращает значение False , если файл удалить не удалось или файл не существует

function ExtractFileExt (const FileName: string): string;

Функция возвращает расширение файла

function ExtractFileName (const FileName: string) : string;

Извлекает имя и расширение файла, содержащегося в параметре FileName

function ExtractFilePath( const FileName: string): string;

Функция возвращает полный путь к файлу

procedure Erase (var F);

Удаляет файл, связанный с файловой переменной F

function FileSearch (const Name, DirList: string) : string;

Данная процедура производит поиск в каталогах DirList файла Name . Если в процессе выполнения FileSearch обнаруживается искомое имя файла, то функция возвращает в строке типа string полный путь к найденному файлу. Если файл не найден, то возвращается пустая строка

function FileSetAttr (const FileName: string; Attr: Integer): Integer;

Присваивает файлу с именем FileName атрибуты Attr. Функция возвращает 0, если присвоение атрибутов прошло успешно. В противном случае возвращается код ошибки

function FilePos (var F): Longint;

Возвращает текущую позицию файла. Функция используется для нетекстовых файлов. Перед вызовом FilePos файл должен быть открыт

function FileSize (var F): Integer;

FileSize возвращает размер файла в байтах или количество записей в файле, содержащем записи. Перед вызовом данной функции файл должен быть открыт.

Для текстовых файлов функция FileSize не используется

procedure Flush (var F: Text);

Процедура очищает буфер текстового файла, открытого для записи. F— файловая переменная.

Когда текстовый файл открыт для записи с использованием функции Rewrite или Append, Flush очищает выходной буфер, связанный с файлом. После выполнения данной процедуры все символы, которые направлены для записи в файл, будут гарантированно записаны в нем

procedure GetDir(D: Byte; var S: string);

Возвращает число, соответствующее диску, на котором содержится текущий каталог s. о может принимать одно из следующих значений:

0 — по умолчанию (текущий);

Процедура не генерирует код ошибки. Если имя диска в D оказывается ошибочным, то в строке S возвращается значение Х:\, как если бы текущая папка была на этом ошибочно указанном диске

function lOResult: Integer;

Функция возвращает статус последней произведенной операции ввода/вывода, если контроль ошибок выключен

procedure MkDir(S: string);

Процедура создает новый каталог, который описывается в строке S

procedure Rename (var F; NewName: string) ;

Процедура изменяет имя файла, связанного с файловой переменной F. Переменная NewName является строкой типа string или PChar (если включена поддержка расширенного синтаксиса)

procedure RmDir(S: string);

Процедура удаляет пустой каталог, путь к которому задается в строке S. Если указанный каталог не существует или он не пустой, то возникает сообщение об ошибке ввода/вывода

procedure Seek (var F; N: Longint) ;

Перемещает текущую позицию курсора на N позиций. Данная процедура используется только для открытых типизированных или нетипизированных файлов для проведения чтения/записи с нужной позиции файла. Началу файла соответствует нулевой номер позиции. Для добавления новой информации в конец существующего файла необходимо установить указатель на символ, следующий за последним. Для этого можно использовать выражение Seek (F, FileSize(F))

function SeekEof[(var F: Text) ] : Boolean;

Возвращает значение True , если указатель текущей позиции находится на символе конца файла. SeekEof может быть использован только с открытым текстовым файлом

function SeekEoln[ (var F: Text) ] : Boolean;

Возвращает значение True , если указатель текущей позиции находится на символе конца строки.

SeekEoln может быть использован только с открытым текстовым файлом

procedure SetTextBuf (var F: Text; var Buf [; Size: Integer] );

Связывает с текстовым файлом буфер ввода/вывода. F — файловая переменная текстового типа. Каждая файловая переменная текстового типа имеет внутренний буфер емкостью 128 байт, в котором накапливаются данные при чтении и записи. Такой буфер пригоден для большинства операций. Однако при выполнении программ с интенсивным вводом/выводом буфер может переполниться, что приведет к записи операций ввода/вывода на диск и, как следствие, к существенному замедлению работы приложения. SetTextBuf позволяет помещать в текстовый файл F информацию об операциях ввода/вывода вместо ее размещения в буфере. Size указывает размер буфера в байтах. Если этот параметр опускается, то полагается размер, равный SizeOf (Buf). Новый буфер действует до тех пор, пока F не будет связана с новым файлом процедурой AssignFile

Удаляет все позиции, следующие после текущей позиции в файле. А текущая позиция становится концом файла. С переменной F может быть связан файл любого типа за исключением текстового

Понятие же «физического вакуума» в релятивистской квантовой теории поля подразумевает, что во-первых, он не имеет физической природы, в нем лишь виртуальные частицы у которых нет физической системы отсчета, это «фантомы», во-вторых, «физический вакуум» — это наинизшее состояние поля, «нуль-точка», что противоречит реальным фактам, так как, на самом деле, вся энергия материи содержится в эфире и нет иной энергии и иного носителя полей и вещества кроме самого эфира.

В отличие от лукавого понятия «физический вакуум», как бы совместимого с релятивизмом, понятие «эфир» подразумевает наличие базового уровня всей физической материи, имеющего как собственную систему отсчета (обнаруживаемую экспериментально, например, через фоновое космичекое излучение, — тепловое излучение самого эфира), так и являющимся носителем 100% энергии вселенной, а не «нуль-точкой» или «остаточными», «нулевыми колебаниями пространства». Подробнее читайте в FAQ по эфирной физике.

НОВОСТИ ФОРУМА
Рыцари теории эфира
01.10.2020 — 05:20: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ — Upbringing, Inlightening, Education ->
[center][Youtube]69vJGqDENq4[/Youtube][/center]
[center]14:36[/center]
Osievskii Global News
29 сент. Отправлено 05:20, 01.10.2020 г.’ target=_top>Просвещение от Вячеслава Осиевского — Карим_Хайдаров.
30.09.2020 — 12:51: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ — Upbringing, Inlightening, Education ->
[center][Ok]376309070[/Ok][/center]
[center]11:03[/center] Отправлено 12:51, 30.09.2020 г.’ target=_top>Просвещение от Дэйвида Дюка — Карим_Хайдаров.
30.09.2020 — 11:53: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ — Upbringing, Inlightening, Education ->
[center][Youtube]VVQv1EzDTtY[/Youtube][/center]
[center]10:43[/center]

интервью Раввина Борода https://cursorinfo.co.il/all-news/rav.
мой телеграмм https://t.me/peshekhonovandrei
мой твиттер https://twitter.com/Andrey54708595
мой инстаграм https://www.instagram.com/andreipeshekhonow/

[b]Мой комментарий:
Андрей спрашивает: Краснодарская синагога — это что, военный объект?
— Да, военный, потому что имеет разрешение от Росатома на манипуляции с радиоактивными веществами, а также иными веществами, опасными в отношении массового поражения. Именно это было выявлено группой краснодарцев во главе с Мариной Мелиховой.

[center][Youtube]CLegyQkMkyw[/Youtube][/center]
[center]10:22 [/center]

Доминико Риккарди: Россию ждёт страшное будущее (хотелки ЦРУ):
https://tainy.net/22686-predskazaniya-dominika-rikardi-o-budushhem-rossii-sdelannye-v-2000-godu.html

Завещание Алена Даллеса / Разработка ЦРУ (запрещено к ознакомлению Роскомнадзором = Жид-над-рус-надзором)
http://av-inf.blogspot.com/2013/12/dalles.html

[center][b]Сон разума народа России [/center]

[center][Youtube]CLegyQkMkyw[/Youtube][/center]
[center]10:22 [/center]

Доминико Риккарди: Россию ждёт страшное будущее (хотелки ЦРУ):
https://tainy.net/22686-predskazaniya-dominika-rikardi-o-budushhem-rossii-sdelannye-v-2000-godu.html

Завещание Алена Даллеса / Разработка ЦРУ (запрещено к ознакомлению Роскомнадзором = Жид-над-рус-надзором)
http://av-inf.blogspot.com/2013/12/dalles.html

[center][b]Сон разума народа России [/center]

MkDir — Процедура Delphi

Данный урок будет о том, как работать с файлами и с каталогами. Эти знания нам понадобятся в дальнейшем при работе с записями, поэтому логично рассказать об этом прямо сейчас. Кроме того, вопросы относительно файлов и папок возникают достаточно часто.

Вспомним, о чём, собственно, речь.

Для обычного пользователя, который не занимается программированием, знать о файлах и папках много не нужно. Достаточно иметь базовые представления, что это такое, как это используется, и какие возможны операции. Однако при программировании необходимо понимание того, что находится «внутри» и как всё это работает.
Итак, файл. Существуют сотни определений этого слова, но все они крутятся вокруг одно и того же. Файл (file) — это совокупность байтов, хранящаяся во внешней памяти и имеющая своё имя. Каждый файл мы можем найти именно по его имени. Каталог (папка, директория — folder, directory) — это своеобразный контейнер для файлов и для других папок. Каждая папка считается абсолютно «резиновой», т.е. мы можем класть в неё файлы до тех пор, пока есть место на диске: объём папки не ограничен. Эти два ключевых понятия неразрывно связаны между собой. В рамках одной папки имена файлов уникальны, т.е. не может быть двух файлов с одним именем. Следует отметить, что регистр, в котором написаны имена файлов и папок, играет свою роль. В операционной системе Windows заглавные и строчные буквы не различаются и к файлу file.txt можно запросто обратиться FILE.TXT и даже fIlE.TxT — система это прекрасно поймёт и проведёт Вас к одному и тому же файлу. Однако в некоторых других операционных системах этот принцип не работает — FILE.TXT и file.txt — два совершенно разных файла. Говорить о том, какой вариант лучше, можно долго — у каждого варианта есть свои преимущества и свои недостатки. Где ещё мы думаем или, наоборот, не задумываемся о регистре? Язык Pascal регистро-независимый: можно писать в любом регистре — как больше нравится или как удобнее. Код, написанный в любом регистре, интерпретируется совершенно одинаково. Речь не идёт, конечно, о строках и символах: при их обработке регистр, естественно, важен.
Что ещё мы должны знать? Каждый файл имеет расширение. Как правило, это 3 символа, хотя современные файловые и операционные системы позволяют делать его и большей длины. У файлов и папок есть атрибуты — некоторые свойства. Кроме того, файловая система хранит некоторую дополнительную информацию о файлах и папках — дата и время создания, открытия, изменения файла, автора и пр.
Ну что же, вроде бы основные моменты вспомнили. Теперь начнём постепенно разбираться, как же со всем этим хозяйством можно работать в Delphi.

Текстовая обработка: пути и имена файлов

Для начала давайте узнаем, где мы вообще находимся. Я имею ввиду полный путь к исполняемому файлу нашей программы. Совершенно логично, что спрашивать нужно у самого приложения, т.е. у объекта Application. Свойство называется ExeName. Не обращайте внимания, что по названию это имя файла — вовсе нет, это самый полный путь к нему.

Edit1.Text:=Application.ExeName;
В качестве результата будет например следующее: C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects\Project1.exe.

Уже неплохо, согласитесь? Ориентация в пространстве — одна из важных функций. Есть и другой способ получить ту же самую информацию — функция ParamStr() с параметром 0.

Edit1.Text:=ParamStr(0);
Если никогда не слышали о командных параметрах — не волнуйтесь. Всему своё время. Просто используйте первый вариант. Идём дальше.

Что нам ещё нужно? Да много чего на самом деле! Например, мы хотим узнать-таки имя исполняемого файла нашей программы. Да, Вы знаете, под каким именем сохранён Ваш проект — именно так и называется исполняемый файл, но только расширение другое — exe. Однако кто сказал, что этот файл будет называться именно так всю свою жизнь? Например, в дистрибутив программа может быть включена совершенно под другим именем. Вывод: «жёстко» указывать имя в коде не пойдёт — будем брать его динамически. Откуда его можно взять? Да вот из пути, который мы только что получили! Нам поможет функция, название которой именно это и означает: «извлечь имя файла» — ExtractFileName(). Единственный параметр — путь к файлу. Итак, пробуем:

Edit1.Text:=ExtractFileName(Application.ExeName);
Ага, Project1.exe. Ловкость рук и никакого мошенничества. А Вы, уже было, приготовились открывать урок про работу со строками, и писать цикл по строке? :-) На самом деле, эта функция так и работает, но код уже написали давным-давно за нас.

Следующий логичный вопрос. Имя файла знаем, а как бы нам узнать только путь? Правильно, всё очень просто: «извлечь путь к файлу» — ExtractFilePath(). Параметр — снова путь:

Edit1.Text:=ExtractFilePath(Application.ExeName);
Получили C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects\. Что ещё для счастья нужно? Казалось бы, ничего? Ан-нет, во многих случаях в таком виде путь неприемлем. Слеш в конце лишний. Можно его удалить вручную, а можно использовать другую функцию — ExtractFileDir(). Всё то же самое, только она вернёт нам путь без слеша на конце:

Edit1.Text:=ExtractFileDir(Application.ExeName);
Результат: C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects.

У Вас наверняка есть своё рабочее место — часть комнаты дома или в офисе: стол с компьютером, кресло. Есть ещё и виртуальный рабочий стол. Программы в этом плане не обделены — у них тоже есть своё рабочее место, которое называется рабочим каталогом. Что это такое? Это та папка, которую программа считает текущей. Т.е. если никуда не ходить, то мы будем работать прямо в этой папке. Что это даёт? Это позволяет обращаться к этому уголку дискового пространства напрямую: вместо указания полного пути к файлу — только его имя. Хотим перейти в подкаталог — пожалуйста, скажите только его имя. По умолчанию рабочим каталогом программы считается тот, в котором расположен её исполняемый файл. Узнать текущий каталог можно функцией GetCurrentDir() — как всегда, логичное название («получить текущую директорию»):

Edit1.Text:=GetCurrentDir();
В моём случае это C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects. К примеру, если в этой папке создать файл new.txt, то к нему можно будет обратиться прямо new.txt, а не писать полный путь C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects\new.txt. Если есть подкаталог Data, то зайти в него — просто Data\ вместо длинного C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects\Data\. Предчувствую вопрос: а как перейти на уровень выше? Предыдущий уровень обозначается двумя точками, поэтому «..\» — это C:\Documents and Settings\Андрей\Мои документы\RAD Studio. Ну а повторив такой переход несколько раз, придём в корень диска C:. Не лишним будет также сказать, что есть и обозначение текущего каталога — одна точка («./»). Позже, когда мы попробуем получить список файлов, эти тонкости всплывут.

Ну а теперь главное. Запомните, что рабочий каталог программы вовсе не обязан быть именно в папке с exe-файлом. Этот каталог можно легко изменить — если заглянуть в свойства ярлыка к любой программе, там есть поле «Рабочая папка». Изменение этого пути приведёт к смене рабочего каталога. К чему это ведёт, надеюсь понятно: программа начнёт обращаться к несуществующим данным, сохранять всё не там, где нужно — бардак в общем. Это одна из частых ошибок, о которой забывают, а потом не могут понять, откуда столько проблем.

Как изменить рабочий каталог? Думаю, сами догадались — функцией SetCurrentDir(). Пример:

SetCurrentDir(‘../../../’);
Edit1.Text:=GetCurrentDir();

Здесь мы поднялись на три уровня вверх. Теперь наш рабочий каталог — C:\Documents and Settings\Андрей. Аналог этой функции — ChDir(). Вы всегда можете проверить свои догадки относительно того пути, куда попадёте, в любом файловом менеджере или в оболочке — в том же Проводнике. Так, например, путь C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects\..\..\RAD Studio\ вполне законный и ничем не отличается от других.

Имена файлов и папок можно обрабатывать и изменять так, как Вам требуется. Однако есть несколько полезных функций, которые сильно облегчают работу.

Функция ExtractFileExt() позволяет извлечь расширение файла. Ext — сокращение от англ. extension — расширение. Обратите внимание, что функция возвращает расширение с первым символом точкой:

Edit1.Text:=ExtractFileExt(Application.ExeName);
Этот код выдаст «.exe».

Помимо извлечения расширения часто требуется его изменить. Например, если нужно пересохранить файл в другой формат, изменится именно его расширение, а имя останется прежним. Есть и такая функция — ChangeFileExt(). Первый параметр — строка с именем или путём к файлу, второй — новое расширение. Пример:

Edit1.Text:=ChangeFileExt(Application.ExeName,’.txt’);
В данном случае получим C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects\Project1.txt.

Пожалуй, об основных моментах побеседовали. Пока что мы работали только с именами и путями. Теперь перейдём непосредственно к работе с файлами.

Есть ли, с чем работать?

Пожалуй, одно из самых частых действий — проверка, а есть ли вообще такой файл на диске? Действительно, от этого многое зависти. Если его нет, а требуется записать данные, то файл нужно создать. А если он есть, то надо решить, что делать с его прежним содержимым.

Проверка существования файла выполняется функцией FileExists() — «файл существует?». Возвращаемое значение — логическое (Boolean).

if FileExists(‘new.txt’) then
ShowMessage(‘Файл существует.’)
else
ShowMessage(‘Файл отсутствует.’);

Путь к файлу может быть как абсолютным (полный путь), так и относительным (от рабочего каталога).

Как видите, всё элементарно. А как узнать, есть ли папка? Да всё то же самое, только вместо File — Directory: DirectoryExists():

if DirectoryExists(‘Data’) then
ShowMessage(‘Папка существует.’)
else
ShowMessage(‘Папки нет.’);

Файлы и папки — понятия разные, поэтому и функии для проверки разные. Вполне может существовать папка new.txt и файл Data (без расширения).
О том, что все так любят делать.

Догадались, о чём пойдёт речь? Да-да, именно об удалении. Сломать проще, чем построить. Однако удалять ненужное — благое дело. С удалением всё не так просто, как с проверкой существования. Когда Вы пытаетесь удалить файл, какая-нибудь программа может его использовать. Естественно, файловая система удалить его не позволит.
Чтобы удалить файл, следует воспользоваться функцией DeleteFile(). Параметр — путь к файлу. Функция возвращает True, если файл успешно удалился, и False, если сделать этого не получилось.

if DeleteFile(‘text.doc’) then
ShowMessage(‘Файл удален.’)
else
ShowMessage(‘Не удалось удалить файл.’);

Для удаления папок используется функция RemoveDir():

if RemoveDir(‘Data’) then
ShowMessage(‘Папка удалена.’)
else
ShowMessage(‘Не удалось удалить папку.’);

Есть и альтернатива — процедура RmDir(), однако об успешности удаления она не сообщает.

О том, как создавать папки

Пришли к главному — как создавать папки и файлы, как записывать в них информацию и читать её оттуда.

Начнём с того, как создавать папки. Здесь всё достаточно просто. Создать папку позволяет функция CreateDir() и процедура MkDir(). Аналогично удалению, первая может сказать о том, получилось ли создать, а вторая лишь молча попробует сделать своё дело.

CreateDir(‘Documents’);
Есть и более интересная модификация — функция ForceDirectories(). Она позволяет создать сразу целую цепочку вложенных друг в друга папок. Например, мы хотим создать папку Files, в ней Documents, а в последней — Срочное. Вариант с использованием MkDir():

MkDir(‘Files’);
MkDir(‘Files\Documents’);
MkDir(‘Files\Documents\Срочное’);

Неудобно, согласитесь? И это только 3 папки. А бывают случаи, когда нужны цепочки и длиннее. Функция ForceDirectories() автоматически создаёт всё недостающее по указанному пути. Одна особенность — функция требует на вход полного (абсолютного) пути. Для нашего примера:

ForceDirectories(GetCurrentDir()+’\Files\Documents\Срочное’);
В этом случае получаем C:\Documents and Settings\Андрей\Мои документы\RAD Studio\Projects\Files\Documents\Срочное.
О том, как создавать файлы и работать с их содержимым

С файлами не всё так просто, как с папками. Это очевидно хотя бы из того, что папка — это просто оболочка с именем. У файла же есть ещё и содержимое. Прежде чем рассказать о механизме работы с файлами, нужно ввести одно важное понятие.

Под указателем в программирование понимается некоторая ссылка, которая может однозначно привести нас к какому-либо объекту. Указатели бывают разные. Например, указатель на ячейку памяти, в которой хранятся какие-либо данные. В этом случае указатель хранит адрес этой ячейки. Указатели существуют во многих операциях, без них доступ к данным невозможен. В реальной жизни указатель можно сравнить с адресом дома, с номером комнаты. Если нам известно, куда идти, то мы туда придём и сделаем то, что нужно. Если указатель (адрес) потерян, найти место проблематично, а то и вовсе невозможно. При работе с файлами тоже используются своего рода указатели. Дело в том, что работа с файлом делится на несколько этапов. Сначала файл нужно открыть. Без этого нельзя ни прочитать из него данные, ни записать их в него. Когда файл открыт, с его содержимым можно выполнять требуемые действия. По окочании работы файл нужно закрыть. Железное правило: не забывайте закрывать открытые файлы! Весь процесс можно увидеть и в реальной жизни: открыл дверь, зашёл, что-то сделал, вышел, закрыл дверь. Если файл не закрыть, можно его заблокировать: система будет думать, что он занят программой, однако программа уже завершила работу и потеряла указатель на него. Результат: открыть файл уже не получится. Лечится такая ситуация либо перезагрузкой системы, либо использованием специальных программ типа File Unlocker, которые восстанавливают доступ к занятым файлам. А теперь начнём разбираться, как работать с файлами.

1. Объявление указателя.

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

var имя_указателя: File of тип_данных;
В качестве типа данных задаётся тот тип, переменную которого можно считать одной записью в файле. Это означает, что Вы изначально подразумеваете файл разбитым на некоторое количество записей. Именно с каждой такой записью будут выполняться все операции: добавление записи в файл или удаление записи из него. Обычный текстовый файл — это набор байтов: каждый символ кодируется один байтом (не принимая в расчёт файлы, содержащие текст в формате Юникода), поэтому текстовый файл описывается так:

var имя_указателя: File of Byte;
Вместо Byte можно написать Char. С последним работать удобнее, если в файле записан текст. Поскольку чаще всего приходится работать именно с текстовыми файлами, был введён отдельный тип данных — TextFile:

var F: TextFile;
Указатели чаще всего называют буквой F (file).

Итак, указатель есть. Переходим к следующему шагу.

2. Установка связи с файлом.

Этот этап можно сравнить с поиском двери нужного Вам номера. Связь устанавливается процедурой AssignFile():

AssignFile(указатель, ‘путь к файлу’);
Первый параметр — указатель, который мы объявили в п.1. Путь к файлу может как абсолютным, так и относительным.

После этой операции мы готовы к открытию файла.

3. Открытие файла.

Открытие — не такая простая операция. Она может выполняться в трёх разных режимах.

Rewrite — перезапись файла (в т.ч. создание несуществующего файла). Подразумевает очистку содержимого файла и установку текущей позиции (её тоже называют указателем) в начало файла.

Reset — открытие файла только для чтения. Указатель устанавливается в начало файла.

Append — добавление. Используется для записи данных в конец файла, не затрагивая существующие данные. Указатель ставится в конец.

Что за указатель тут используется? Это не тот, который даёт нам доступ к файлу. Представьте внутреннее содержимое файла как текст. В текстовом редакторе есть курсор, который находится в какой-то конкретной позиции. С файлом то же самое: есть невидимый курсор, посредством которого можно работать с содержимым. Если требуется записать данные в файл, курсор ставится в нужную позицию и далее выполняется запись. Если нужно прочитать — перемещаемся в нужное место и, шаг за шагом, считываем нужные данные. Указатель при этом каждый раз движется вперёд. Рано или поздно он достигнет конца файла.

Функции вроде OpenFile нет — вместо неё есть 3 функции с названиями, приведёнными выше: Rewrite(), Reset(), Append(). Единственный обязательный параметр всех этих функций — указатель на наш файл, причём тот, с помощью которого уже установлена связь с помощью AssignFile().

4. Закрытие файла.

Закрытие выполняется помощью CloseFile() передачей переменной-указателя на файл.

Вот и основные сведения о том, как работать с файлами. При работе следует заботиться обо всём, что может произойти. Так, например, если попытаться открыть файл для чтения функцией Reset(), которого не существует, произойдёт ошибка.

Пример 1. Создадим пустой текстовый файл.

AssignFile(F,’new.txt’);
Rewrite(F);
CloseFile(F);
Мы объявили переменную F типа «текстовый файл», далее привязали её к файлу new.txt, сделали перезапись файла и закрыли его. В итоге получен пустой файл.
Набор из трёх команд необходимо выполнять при работе с любым файлом.

Чтение и запись

Для чтения и записи существуют процедуры с понятными именами Read() и Write(). Процедуры необычые: у них неограниченное число параметров. У обеих первым параметров передаётся указатель на файл, а дальше — список переменных (или значений), с которыми нужно выполнить данную операцию. Команда Read() читает одну запись из файла и заносит её в переменную, которая указана вторым параметром. При этом указатель сдвигается на одну позицию. Если указать несколько переменных — в них будут считаны значения по порядку. Функция автоматически распознаёт разделители значений — пробелы, что позволяет с лёгкостью считывать несколько значений из файла. Запись работает аналогично: все переданные значения последовательно записываются в файл.

Помните, что пока Вы не закрыли файл, внесённые изменения в нём не сохраняются!

Пример 2. Запись в файл.

var F: TextFile; a,b: Byte;

AssignFile(F,’new.txt’);
Rewrite(F);
a:=2;
b:=10;
Write(F,’1′,a,’3 ‘,b);
CloseFile(F);

В данном примере показано использование Write(). В результате в файле будет строка «123 10». Были записаны как явно заданные строки, так и значения переменных.

Пример 3. Считывание из файла двух чисел.

var F: TextFile; a,b: Byte;

AssignFile(F,’new.txt’);
Reset(F);
Read(F,a,b);
CloseFile(F);

ShowMessage(IntToStr(a)+’ ; ‘+IntToStr(b));
В данном примере файл открывается для чтения (Reset) и из него считываются записанные там значения в переменные a и b. На экран будет выведено сообщение «123 ; 10».

Процедуры Read() и Write() не проверяют типов данных, которые используются при работе с файлом. Так что можно напрямую записывать числа, не преобразуя их в строки, и обратно из строк в числа при чтении.

Итак, записывать и читать данные научились. Но хватит ли этого для решения любых задач? Нет.

Гораздо чаще требуется работать с файлами построчно, т.е. считывать и записывать целые строки. Реакция функций на пробелы-разделители будет только вставлять палки в колёса. На помощь приходят функции ReadLn() и WriteLn(). Ln — сокращение от line (строка). ReadLn() читает целую строку из файла, а WriteLn() записывает данные и вставляет после них признаки конца текущей строки и начала новой. В остальном работа этих функций точно такая же.

Когда выполняется чтение файла, указазатель («курсор») перемещается автоматически. Понятно, что в какой-то момент мы придём к концу файла и дальше читать уже будет нечего. Чтобы отследить это состояние, используется функция EOF() — сокращение от end of file (конец файла). Передаём указатель на файл и узнаём, дошли ли до конца. Что может быть проще? Таким образом, чтение файла легко записывается в цикл.

Пример 4. Считывание всего файла в ListBox.

var F: TextFile; S: String;

ListBox1.Clear;
AssignFile(F,’new.txt’);
Reset(F);
while not EOF(F) do
begin
ReadLn(F,S);
ListBox1.Items.Add(S)
end;
CloseFile(F);

Разберём пример построчно:

Очищаем ListBox.
Связываемся с файлом new.txt.
Открываем файл для чтения (указатель в начале файла).
До тех пор, пока не дошли до конца файла.
. читаем очередную строку в переменную S.
и добавляем эту строку в ListBox.
Закрываем файл.
Механизм простой, и, надеюсь понятный.

Пример 5. Сохранение всех строк из поля Memo в текстовый файл.

var F: TextFile; I: Integer;

AssignFile(F,’test.txt’);
Rewrite(F);
for I := 0 to Memo1.Lines.Count-1 do
WriteLn(F,Memo1.Lines[I]);
CloseFile(F);

Установили связь с файлом.
Перезаписали файл.
Проходим по всем строкам Memo1.
. и переписываем каждую строку в файл.
Закрываем файл.
Считаю необходимым напомнить, что операции сохранения и загрузки из файла в Memo и ListBox предусмотрены. Эквиваленты для данных примеров:

ListBox1.Items.LoadFromFile(‘new.txt’);
Memo1.Lines.SaveToFile(‘test.txt’);

Заключение

Мы рассмотрели работу с файлами и каталогами. Научились работать с путями и именами файлов, а также узнали, как записывать информацию в файлы, и как считывать её оттуда. Конечно, это далеко не всё. Ещё множество вопросов осталось за кадром. Как определить объём файла? Как скопировать, переместить, переименовать файл? Речь об этом пойдёт во второй части данной темы, однако в следующем уроке мы вернёмся к работе с записями.

Для усвоения пройденного предлагаю создать следующую программу.

На форме два поля для ввода текста. В первое вводится путь к некоторой папке, а во второе — текстовая строка, содержащая символ «*» (звёздочка). Дополнительно (с помощью каких-либо компонентов) вводятся два числа. Требуется в указанной папке создать текстовые файлы с именами из второго поля, заменив звёздочку на числа из заданного диапазона. При этом, если такой файл уже был на диске, нужно дописать в него текущее время, а если его не было — то и дату, и время.

Подсказка: текущее время в виде строки можно получить как TimeToStr(Now), а дату — DateToStr(Now).

Примерный вид окна программы приведён на рисунке справа. Для указанных исходных данных на диске C:\ будут созданы файлы Test1.txt, Test2.txt, . Test5.txt.

Типы, функции и процедуры Delphi для работы с файлами.

Содержание:


Процедуры и функции для работы с файлами.


Тип TSearchRec.


Тип TWin32FindData.


Процедуры и функции для работы с файлами

Ниже приведена таблица, содержащая стандартные процедуры и функции Delphi7 для работы с файлами и их краткое описание. Функции в таблице расположены в алфавитном порядке.

Связывает имя внешнего дискового файла с файловой переменной.

procedure AssignFile(var F; FileName: string);

F — имя файловой переменной
FileName — имя файла

Изменяет текущую директорию.

procedure ChDir(const S: string); overload;
procedure ChDir(P: PChar); overload;

Разрывает связь между файловой переменной и внешним дисковым файлом.

procedure CloseFile(var F);

Создает новую директорию.

function CreateDir(const Dir: string): Boolean;

Удаляет файл с диска.

function DeleteFile(const FileName: string): Boolean;

Определяет существует ли указанная директория.

function DirectoryExists(const Directory: string): Boolean;

Возвращает число свободных байт на указанном диске.

function DiskFree(Drive: Byte): Int64;

Drive — номер диска, где 0 = текущий диск, 1 = A, 2 = B . и т.д.

Возвращает размер указанного диска в байтах.

function DiskSize(Drive: Byte): Int64;

Drive — номер диска, где 0 = текущий диск, 1 = A, 2 = B . и т.д.

Возвращает время последней модификации файла (timestamp) в формате операционной системы. Полученное значение может быть преобразовано в формат TDateTime при помощи функции FileDateToDateTime.

function FileAge(const FileName: string): Integer;

Закрывает указанный файл.

procedure FileClose(Handle: Integer);

Создает новый файл.

function FileCreate(const FileName: string): Integer; overload;
function FileCreate(const FileName: string; Rights: Integer): Integer; overload;

Если возвращаемое значение больше 0 функция выполнена успешно и его значение соответствует handle открытого файла. -1 — произошла ошибка открытия файла.
Параметр Rights используется только для Linux. В Windows он игнорируется.

Преобразует значение времени файла (timestamp) из формата операционной системы в TDateTime.

function FileDateToDateTime(FileDate: Integer): TDateTime;

Проверяет существует ли указанный файл.

function FileExists(const FileName: string): Boolean;

Возвращает файловые аттрибуты заданного файла как строку бит. Возвращаемое значение полностью соответствует полю Attr в TSearchRec..

function FileGetAttr(const FileName: string): Integer;

Возвращает время последней модификации файла (timestamp) в формате операционной системы. Используйте её для файла, заданного его handle.

function FileGetDate(Handle: Integer): Integer;

Возвращает TRUE если файл можно открыть только для чтения.

function FileIsReadOnly(const FileName: string): Boolean;

Открывает указанный файл в режиме, заданном при помощи одной из констант File open mode.

function FileOpen(const FileName: string; Mode: LongWord): Integer;

Если возвращаемое значение больше 0 функция выполнена успешно и его значение соответствует handle открытого файла. -1 — произошла ошибка открытия файла.

Читает указанное число байт из файла в буфер. Перед этим файл должен быть открыт при помощи функции FileOpen или FileCreate.

function FileRead(Handle: Integer; var Buffer; Count: Integer): Integer;

Handle — хендл файла, возвращаемый функциями FileCreate или FileOpen
Buffer — буфер
Count — размер буфера

Возвращаемое значение — действительное количество полученных байт. Оно может быть меньше размера буфера.

Ищет файл в указанных папках.

function FileSearch(const Name, DirList: string): string;

Name — короткое имя файла
DirList — список директорий для поиска. Для Windows директории для поиска в списке отделяются друг от друга точкой с запятой, а в Linux — двоеточием.

Возвращаемое значение — полное имя файла. Если файл не найден — пустая строка.

Перепозиционирует позицию чтения/записи в открытом файле. Перед этим файл должен быть открыт при помощи функции FileOpen или FileCreate.

function FileSeek(Handle, Offset, Origin: Integer): Integer; overload;
function FileSeek(Handle: Integer; const Offset: Int64; Origin: Integer): Int64;overload;

Handle — хендл файла, возвращаемый функциями FileCreate или FileOpen
Offset — указывает число байт смещения от Origin, куда будет перепозизиционирована точка.
Origin — определяет три варианта позиционирования:
0 — смещение задается относительно начала файла;
1 — смещение задается относительно текущей позиции;
2 — смещение задается относительно конца файла.

Если FileSeek выполнена успешно, она возвращает новую позицию точки чтения/записи; иначе она возвращает -1.

Устанавливает файловые аттрибуты заданного файла.

function FileSetAttr(const FileName: string; Attr: Integer): Integer;

Значение Attr формируется комбинацией соответствующих констант файловых аттрибутов как показано ниже:

Возвращаемое значение — 0; иначе — код ошибки.

Примечание: Значения констант файловых аттрибутов приведены в описании TSearchRec.

Примечание: FileSetAttr доступна только для Windows.

Устанавливаетвремя последней модификации файла (timestamp) в формате операционной системы.

Для Windows:
function FileSetDate(Handle: Integer; Age: Integer): Integer; overload;

Cross-platform:
function FileSetDate(const FileName: string; Age: Integer): Integer; overload;

Handle — handle файла для изменения (Этот синтаксис доступен только для Windows.);
FileName — имя файла;
Age — устанавливаемое время модификации в формате операционной системы. Используйте функцию DateTimeToFileDate для перевод времени из формата TDateTime в формат операционной системы.

Возвращаемое значение — 0; иначе — код ошибки.

Разрешает использовать файл только для чтения.

function FileSetReadOnly(const FileName: string; ReadOnly: Boolean): Boolean;

Записывает содержимое буфера в текущую позицию в файле.

function FileWrite(Handle: Integer; const Buffer; Count: Integer): Integer;

Handle — хендл файла, возвращаемый функциями FileCreate или FileOpen
Buffer — буфер
Count — число байт, передаваемых файлу из буфера

Возвращаемое значение — действительное количество записаных байт или -1 в случае ошибки.

Освобождает память, выделенную под функцию FindFirst и прерывает последовательность FindFirst/FindNext.

Ищет первый файл с заданными аттрибутами в указанной папке.

function FindFirst(const Path: string; Attr: Integer; var F: TSearchRec): Integer;

Path — имя папки и маска имен файлов для поиска, включая wildcard characters. (Например, ‘.\test\*.*’ задает все файлы в текущей папке.)
Attr — аттрибут, указывающий включать в поиск специальные файлы в дополнение к нормальным. Аттрибуты можно комбинировать, складывая значения. Например, (faReadOnly + faHidden).
F — возвращаемый параметр. Результат работы функции.

Возвращаемое значение — 0, если файл найден; иначе — код ошибки.

Возвращает имя следующего файла с параметрами, предварительно заданными функцией FindFirst.

F — возвращаемый параметр. Результат работы функции.

Возвращаемое значение — 0, если файл найден; иначе — код ошибки.

Создает новую папку, включая родительские папки, если они до этого не существовали, и родительские папки.

function ForceDirectories(Dir: string): Boolean;

Возвращает полное имя рабочей папки.

function GetCurrentDir: string;

Возвращает имя рабочей папки.

procedure GetDir(D: Byte; var S: string);

D — номер диска, где 0 = текущий диск, 1 = A, 2 = B, 3 = C . и т.д.
S — возвращаемый параметр. Результат работы процедуры.

Удаляет существующую пустую папку.

function RemoveDir(const Dir: string): Boolean;

Изменяет имя файла.

function RenameFile(const OldName, NewName: string): Boolean

Назначает рабочую папку.

function SetCurrentDir(const Dir: string): Boolean;

Тип TSearchRec

TSearchRec содержит информацию о файле, найденом при помощи функции FindFirst или FindNext.

Тип TSearchRec определяет информацию о файле, найденую путем вызова функции FindFirst или FindNext. Если файл найлен, поля параметров TSearchRec изменяются в соответствии с найденным файлом.

Attr — представляет файловые аттрибуты файла. Проверяйте параметр Attr на следующие константы аттрибутов или их значения чтобы узнать какие аттрибуты назначены данному файлу.

В Windows константы аттрибутов полностью соответствуют файловым аттрибутам DOS.

Наименование Тип
модуль
Описание
AssignFile процедура
System
ChDir процедура
System
CloseFile процедура
System
CreateDir функция
SysUtils
DeleteFile функция
SysUtils
DirectoryExists функция
SysUtils
DiskFree функция
SysUtils
DiskSize функция
SysUtils
File mode константы
System
Используются для открытия и закрытия дисковых файлов.

const fmClosed = $D7B0; // closed file
const fmInput = $D7B1; // reset file (TTextRec)
const fmOutput = $D7B2; // rewritten file (TTextRec)
const fmInOut = $D7B3; // reset or rewritten file (TFileRec)
const fmCRLF = $8; // DOS-style EoL and EoF markers (TTextRec)
const fmMask = $D7B3; // mask out fmCRLF flag (TTextRec)

Эти константы используются в первую очередь в Delphi коде, где поле Mode в TFileRec и TTextRec содержит одно из этих значений.

File open mode константы
SysUtils
Константы режима открытия файла используются для контроля режима доступа к файлу или потоку.

Для Windows:

Эти константы используются для конроля режима совместного доступа при открытии файла или потока.

TFileStream конструктор имеет параметр Mode в котрый вы можете прописать одну из следующих констант:

Константа Описание
fmCreate Если файл уже существует, то он открывается для записи, иначе создается новый файл. В отличие от других констант, которые декларируются в модуле SysUtil, эта константа декларируется в модуле classes.
fmOpenRead Открываетдоступ только для чтения.
fmOpenWrite Открываетдоступ только для записи.
fmOpenReadWrite Открывает доступ для чтения и записи.
fmShareCompat Compatible with the way FCBs are opened. Не используйте этот режим в кросс-платформенных приложениях.
fmShareExclusive Доступ к чтению и записи запрещен.
fmShareDenyWrite Доступ для записи запрещен.
fmShareDenyRead Доступ для чтения запрещен. Не используйте этот режим в кросс-платформенных приложениях.
fmShareDenyNone Открывает полный доступ для других.
FileAccessRights пременная Points to the command-line arguments specified when the application is invoked. Только для Linux. В Windows эта переменная игнорируется.
FileAge функция
SysUtils
FileClose процедура
SysUtils
FileCreate функция
SysUtils
FileDateToDateTime функция
SysUtils
FileExists функция
SysUtils
FileGetAttr функция
SysUtils
FileGetDate функция
SysUtils
FileIsReadOnly функция
SysUtils
FileOpen функция
SysUtils
FileRead функция
SysUtils
FileSearch функция
SysUtils
FileSeek функция
SysUtils
FileSetAttr функция
SysUtils
FileSetDate функция
SysUtils
FileSetReadOnly функция
SysUtils
FileWrite функция
SysUtils
FindClose процедура
SysUtils
FindFirst функция
SysUtils
FindNext функция
SysUtils
ForceDirectories функция
SysUtils
GetCurrentDir функция
SysUtils
GetDir процедура
System
RemoveDir функция
SysUtils
RenameFile функция
SysUtils
SetCurrentDir функция
SysUtils
Константа Значение Описание
faReadOnly 1 Файлы Только для чтения
faHidden 2 Скрытые файлы
faSysFile 4 Системные файлы
faVolumeID 8 Файлы идентификации тома
faDirectory 16 Файлы папок
aArchive 32 Архивные файлы
faSymLink 64 Символьная ссылка
faAnyFile 71 Любые файлы

Примечание:
Константа faReadOnly из модуля SysUtils имеет то же самое имя, что и константа из модуля Db, определенная в типе TFieldAttribute. Если в своих исходниках вы одновременно используете модули SysUtils и Db, то, чтобы исключить неопределенность, необходимо конкретно указывать из какого модуля вы используете значение константы faReadOnly. В Delphi это записывается так: SysUtils.faReadOnly.

Чтобы проверить файл на определенный аттрибут, комбинируйте значение поля Attr с соотвтствующей константой при помощи оператора AND. Если файл имеет этот аттрибут, результат будет больше 0. Например, если найденый файл является скрытым, то следующие выражения дадут значение TRUE:

Time содержит время последнего изменения файла. Оно может быть преобразовано в формат TDateTime при помощи функции FileDateToDateTime.

Size содержит размер файла в байтах.

Name содержит короткое имя файла с расширением.

FindHandle is an internal handle used to track find state.

FindData (только для Windows) содержит дополнительную информацию, такую как время создания файла, время последнего доступа, а так же длинное и короткое имя файла. См. тип TWin32FindData.

Delphi Неоднозначный перегруженный вызов в MkDir

При попытке вызвать MkDir

появляется следующее сообщение об ошибке:

[Ошибка] DBaseReindexer.dpr(22): неоднозначный перегруженный вызов MkDir

Я пробовал следующие вещи, и все они возвращают ту же ошибку.

От взгляда на источник есть версия, которая берет строку, и версию, которая принимает PChar. Я не уверен, как моя строка будет двусмысленной между этими двумя типами.

Код для воспроизведения ошибки (из комментариев):

Ваш код компилируется в пустом проекте:

Итак, ваша проблема в том, что где-то в вашем коде вы определили несовместимую перегрузку для MkDir . Например, эта программа:

создает следующие ошибки компилятора:

Обратите внимание, как компилятор помогает вам, какие два метода не могут быть устранены. Если вы прочитаете полное сообщение об ошибке компилятора, это приведет вас к причине вашей проблемы.

Старые версии Delphi не дают вам дополнительной информации. Поэтому, если вы находитесь в этом положении, вам придется искать исходный код для дополнительного MkDir .

Обновление

После редактирования вопроса, добавляющего код, мы видим, что несовместимая перегрузка возникает из довольно удивительного источника. Ваш код:

Ну, System автоматически включается в каждую единицу, и это дефект компилятора, который компилятор проходит после предложения uses . Но ошибочное второе включение System является причиной двусмысленности.

Современные версии Delphi исправляют эту проблему, и ваш код приводит к

Очевидно, что решение заключается в удалении ложного использования System .

MkDir — Процедура Delphi

Изучив основные «кирпичики», из которых составляются программные инструкции, а именно — переменные и операторы, мы можем приступить к исследованию вопросов их эффективного расположения в теле программы. Для этих целей рассмотрим вопрос использования подпрограмм.

О подпрограммах в Object Pascal

Важной составной частью программирования в Object Pascal является использование подпрограмм — специальным образом оформленных и логически законченных блоков инструкций. Подпрограмму можно вызывать любое число раз из других мест программы, или из других подпрограмм. Таким образом, использование подпрограмм позволяет сделать исходный код более стройным и наглядным.

Структура подпрограммы похожа на программу в миниатюре: она содержит заголовок, блок объявления переменных и блок инструкций. Из отличий можно выделить лишь невозможность подключать модули (блок uses), а так же ограничения на объявления типов данных: если локальные простые и даже составные типы в подпрограммах вполне допустимы, то более сложные типы — объекты, классы и интерфейсы, локальными быть не могут, а потому в подпрограммах их объявлять нельзя.

Использование подпрограммы состоит из 2 этапов: сначала подпрограмму описывают, а затем, уже в блоке инструкций программы, вызывают. Отметим, что в библиотеке Delphi имеется описание тысяч готовых подпрограмм, описывать которые, разумеется, уже не надо. А их вызовом мы уже неоднократно занимались — достаточно взглянуть на любой пример, где мы встречали инструкции, подобные таким:

write(‘Hello, world!’); readln;

Здесь и write, и readln — стандартные подпрограммы Object Pascal. Таким образом, с вызовом подпрограмм мы уже знакомы. Осталось узнать, как создавать собственные, или пользовательские, подпрограммы. Но прежде отметим, что все подпрограммы делятся на 2 лагеря: процедуры и функции. Мы уже использовали эти термины, и даже давали им описание, однако повторимся: процедуры — это такие подпрограммы, которые выполняют предназначенное действие и возвращают выполнение в точку вызова. Функции в целом аналогичны процедурам, за тем исключением, что они еще и возвращают результат своего выполнения. Результатом работы функции могут быть данные любого типа, включая объекты.

Вместе с тем, значение, возвращаемое функцией, можно проигнорировать, в таком случае она ничем не будет отличаться от процедуры. Разумеется, при этом функция все-таки должна выполнить какое-либо действие, сказывающееся на выполнении программы, иначе она потеряет всякий смысл. С другой стороны, процедуры могут возвращать значения через свои параметры — например, как это делает DecodeDate. Таким образом, различия между процедурами и функциями в современном программировании весьма призрачны.

Как процедурам, так и функциям могут передаваться данные для обработки. Делается это при помощи списка параметров. Список параметров в описании подпрограммы и список аргументов, указываемых при ее вызове должен совпадать. Иначе говоря, если в описании определено 2 параметра типа Integer, то, вызывая такую подпрограмму, в качестве аргументов так же следует указать именно 2 аргумента и именно типа Integer или совместимого (скажем, Word или Int64).

ПРИМЕЧАНИЕ
На самом деле, Object Pascal позволяет довольно гибко обращаться с аргументами, для чего имеются различные методы, включая «перегружаемые» функции, значения параметров по умолчанию и т.д. Тем не менее, в типичном случае, количество, тип, и порядок перечисления аргументов при объявлении и при вызове процедуры или функции, должны совпадать.

Любые подпрограммы выполняются до тех пор, пока не будет выполнена последняя инструкция в блоке подпрограммы, или пока в ее теле не встретится специальная процедура exit. Процедура exit досрочно прерывает выполнение подпрограммы и возвращает управление инструкции, следующей за вызовом данной подпрограммы.

Процедуры

Итак, начнем исследование подпрограммы с процедур. Как уже было отмечено, процедуру надо описать. Описание процедуры состоит из заголовка и тела процедуры.

Заголовок состоит из ключевого слова procedure, за которым следует имя процедуры и, при необходимости, список параметров, заключенных в круглые скобки:

Вслед за заголовком может следовать блок объявления локальных меток, типов и переменных. Локальными они называются потому, что предназначены исключительно для этой процедуры.

ПРИМЕЧАНИЕ
Вопросы локальных и глобальных переменных, и вообще видимости в программах, будет рассмотрен позже в этой главе.

После заголовочной части следует тело процедуры, заключаемое в begin и end. Таким образом, исходный код процедуры может выглядеть примерно таким образом:

procedure TriplePrint(str: string); var i: integer; begin for i := 1 to 3 do begin writeln(‘»‘+str+'»‘); end; // конец цикла for end; // конец процедуры TriplePrint

Здесь мы определили процедуру TriplePrint, которая будет трижды выводить переданную ей в качестве аргумента строку, заключенную в двойные кавычки. Как видно, данная процедура имеет все составные части: ключевое слово procedure, имя, список параметров (в данном случае он всего один — строковая переменная str), блок объявления собственных переменных (целочисленная переменная i), и собственное тело, состоящее из оператора цикла for.

Для использования данной процедуры в любом месте программы достаточно написать инструкцию вызова процедуры, состоящую из имени процедуры и списка аргументов, например:

Отметим так же, что рассмотренная нами процедура сама содержит вызов другой процедуры — writeln. Процедуры могут быть встроенными. Иначе говоря, объявление одной процедуры можно помещать в заголовочную часть другой. Например, наша процедура TriplePrint может иметь вспомогательную процедуру, которая будет «подготавливать» строку к выводу. Для этого перед объявлением переменной i, разместим объявление еще одной процедуры. Назовем ее PrepareStr:

procedure PrepareStr; begin str := ‘»‘+str+'»‘; end;

Отметим, что переменная str, хотя и не передается этой процедуре в качестве параметра, тем не менее может в ней использоваться, поскольку данная процедура является составной частью процедуры TriplePrint, внутри которой данная переменная доступна для использования.

Таким образом, мы получаем две процедуры, одна из которых (TriplePrint) может использоваться во всей программе, а другая (PrepareStr) — только внутри процедуры TriplePrint. Чтобы преимущество использования процедур было очевидно, рассмотрим их на примере программы, которая будет использовать ее неоднократно, для чего обратимся к листингу 6.1 (см. так же пример в Demo\Part1\Procs).

Листинг 6.1. Использование процедур

program procs; <$APPTYPE CONSOLE>procedure TriplePrint(str: string); procedure PrepareStr; begin str := ‘»‘+str+'»‘; end; var i: integer; begin PrepareStr; for i := 1 to 3 do begin writeln(str); end; end; // конец процедуры TriplePrint begin // начало тела основной программы TriplePrint(‘Hello. ‘); // первый вызов TriplePrint TriplePrint(‘How are you. ‘); // 2-й вызов TriplePrint(‘Bye. ‘); // 3-й readln; end.

Очевидно, что если бы не процедура, то нам трижды пришлось бы писать цикл, свой для каждого слова. Таким образом, процедуры позволяют использовать единожды написанный код многократно, что существенно облегчает написание программ.

Функции

Подобно процедурам, описание функции состоит из заголовка и тела. Однако описание заголовка имеет 2 отличия: прежде всего, для функций используется ключевое слово function. Кроме того, поскольку функции всегда возвращают результат, завершается строка заголовка типом возвращаемого значения. Таким образом, для объявления функции мы получаем следующий синтаксис:

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

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

function cube(value: integer) : integer; result := value * value * value; >

Здесь определена функция, имеющая параметр value типа целого числа, которое она возводит в третью степень путем троекратного умножения, и результат присваивается специальной переменной result. Таким образом, чтобы в любом месте программы вычислить значение числа в 3-й степени, достаточно написать такое выражение:

В результате выполнения этого выражения переменной x будет присвоено значение 27. Данный пример иллюстрирует использование функций в классическом случае — для явного вычисления значения переменной. Однако функции могут использоваться в выражениях и напрямую. Например, можно поставить вызов функции cube в каком-либо месте арифметического выражения подобно обычной переменной:

Подобно процедурам, функции так же могут быть встроенными. Кроме того, функции могут включать в себя не только локальные функции, но и процедуры. Впрочем, верно и обратное — в процедурах могут использоваться локальные функции. Например, в той же процедуре TriplePrint можно было бы использовать не процедуру, а функцию PrepareStr, которая принимала бы строку и возвращала ее же в кавычках:

procedure TriplePrint(str: string); function PrepareStr(s: string) : string; begin result := ‘»‘+s+'»‘; end; var i: integer; begin for i := 1 to 3 do begin writeln(PrepareStr(str)); // функция использована как переменная end; end;

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

function cube(value: integer) : integer; cube := value * value * value; >

В данном случае оба варианта будут вести себя полностью аналогично. Различия проявляются лишь в том случае, если использовать такую переменную в выражениях в теле функции. В подобных случаях следует использовать именно переменную result, а не имя функции, поскольку использ0овании имени функции в выражении внутри самой функции приведет к ее рекурсивному вызову.

Рекурсия

Таким образом мы подошли к теме рекурсии — вызову подпрограммы из самой себя. Это не является ошибкой, более того, целый ряд алгоритмов решить без рекурсии вообще было бы затруднительно.

Рассмотрим вопрос рекурсии на следующем примере:

function recfunc(x: integer) : integer begin dec(x); // функция декремента, уменьшает целое на 1 if x > 5 then x := recfunc(x); result := 0; // возвращаемое значение тут не используется end;

Здесь мы объявили функцию recfunc, принимающую один аргумент, и вызывающую саму себя до тех пор, пока значение этого аргумента больше 5. Хотя на первый взгляд может показаться, что такое поведение функции похоже на обычный цикл, на самом деле все работает несколько по-иному: если вы вызовите ее со значением 8, то она выдаст вам 3 сообщения в следующей последовательности: 5, 6, 7. Иначе говоря, функция вызывала саму себя до тех пор, пока значение x было больше 5, и собственно вывод сообщений начала 3-я по уровню получившейся вложенности функция, которая и вывела первое сообщение (в данном случае им стало 5, т.е. уменьшенное на единицу 6).

Чтобы представить себе более наглядно, как работает рекурсивный вызов, дополним эту функцию выводом комментариев, а так же счетчиком глубины рекурсии. Для этого мы, во-первых, задействуем возвращаемое функцией значение, а во-вторых, добавим еще один параметр, который и будет счетчиком. Результат проделанной работы приведен в листинге 6.2.

Листинг 6.2. Рекурсия с комментариями

program recurse; <$APPTYPE CONSOLE>function recfunc(x, depth: integer) : integer; begin dec(x); if x > 5 then begin write(‘Current recursion depth is: ‘); write(depth); write(‘, current x value is: ‘); writeln(x); inc(depth); depth:=recfunc(x, depth); end else writeln(‘End of recursive calls. ‘); write(‘Current recursion depth is: ‘); write(depth); write(‘, current x value is: ‘); writeln(x); dec(depth); result := depth; end; begin recfunc(8,0); readln; end.

Исходный код находится в Demo\Part1\Recurse, там же находится и исполняемый файл recurse.exe, результат работы которого вы можете увидеть на своем экране.

Использование параметров

Параметры в процедурах и функциях могут применяться не только по своему прямому предназначению — для передачи данных подпрограмме, но так же могут быть использованы для возвращения значений. Подобное их использование может быть вызвано, например, необходимостью получить более одного значения на выходе функции. Синтаксис объявления параметров в таком случае несколько отличается от стандартного — перед именем параметра следует использовать ключевое слово var:

procedure Circle (square: real; var radius, length: real);

Данная процедура принимает «на обработку» одно значение — площадь (square), а возвращает через свои параметры два — радиус (radius) и длину окружности (length). Практическая ее реализация может выглядеть таким образом:

procedure Circle (square: real; var radius, length: real); begin radius := sqrt(square / pi); // функция pi возвращает значение числа ? length := pi * radius * 2; end;

Теперь, чтобы воспользоваться этой функцией, следует объявить в программе 2 переменные, которые будут переданы в качестве аргументов этой процедуре и получат результаты. Их имена не важны, важно лишь, чтобы они были такого же, или совместимого типа, т.е. вещественные, например:

var r,l: real; . Circle(100,r,l);

После вызова функции Circle, переменные r и l получат значения радиуса и длины окружности. Остается их вывести при помощи writeln. Исходный код программы приведен в листинге 6.3.

Листинг 6.3. Процедура с параметрами

program params; <$APPTYPE CONSOLE>procedure Circle (square: real; var radius, length: real); begin //функция sqrt извлекает корень, а функция pi возвращает значение числа ? radius := sqrt(square / pi); length := pi * radius * 2; end; var r,l: real; begin Circle(100,r,l); writeln(r); writeln(l); readln; end.

Запустив такую программу, можно убедиться, что она работает и выводит верные результаты, однако вид у них получается довольно-таки неудобочитаемый, например, длина окружности будет представлена как «3,54490770181103E+0001». Чтобы сделать вывод более удобным для восприятия, нам понадобится функция FloatToStrF. С ее помощью мы можем определить вывод числа на свое усмотрение, например:

Кроме того, не помешало бы указать, где радиус, а где — длина окружности. Для этого модернизируем строки вывода результатов следующим образом:

writeln(‘Radius is: ‘+FloatToStrF(r,ffFixed,12,8)); writeln(‘Length is: ‘+FloatToStrF(l,ffFixed,12,8));

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

. var s,r,l: real; begin write(‘Input square: ‘); readln(s); Circle(s,r,l); writeln(‘Radius is: ‘+FloatToStrF(r,ffFixed,12,8)); writeln(‘Length is: ‘+FloatToStrF(l,ffFixed,12,8)); readln; end.

В принципе, это уже лучше, однако не помешало бы добавить обработку возможных ошибок ввода. Скажем, площадь должна быть больше 0. Проверку на то, является ли значение s больше нуля, можно производить непосредственно в основном коде программы, но в целях создания более универсального кода, вынесем ее в подпрограмму. Для этого первой инструкцией процедуры Circle должна быть проверка значения площади:

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

function Circle(square: real; var radius, length: real) : boolean; begin result := false; if (square

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

Поскольку программа теперь может получить сведения о том, выполнились ли преобразования на основании возвращаемого функцией Circle булевского значения, остается добавить такую проверку в тело программы. В качестве условия для условного оператора в таком случае подойдет сама функция Circle (на самом деле, условием будет выступать не функция, а как раз возвращаемое ей значение):

if Circle(s,r,l) then begin // вывод end else // сообщить об ошибке

Результатом проделанной работы будет программа, приведенная в листинге 6.4. Она же находится в Demo\Part1\Params.

Листинг 6.4. Функция с параметрами

program params; <$APPTYPE CONSOLE>uses sysutils; //этот модуль соджержит функцию FloatToStrF function Circle(square: real; var radius, length: real) : boolean; begin result := false; if (square

Итак, при помощи ключевого слова var в списке параметров подпрограммы мы можем добиться использования передаваемых аргументов в том блоке, где был произведен вызов данной подпрограммы. В несколько другом аспекте используется ключевое слово const. Фактически, оно объявляет локальную константу, т.е. значение, которое нельзя изменять внутри данной процедуры или функции. Это бывает полезным в том случае, когда такое изменение недопустимо по логике программы и служит гарантией того, что такое значение не будет изменено.

При этом открывается еще одна возможность, связанная с константами, а именно — использование предопределенных значений. Например, можно определить функцию следующим образом:

function MyBetterFunc(val1: integer; const val2: integer = 2); begin result := val1*val2; end;

Обращение же к такой функции может иметь 2 варианта: с указанием только одного аргумента (для параметра val1), или же с указанием обоих:

x := MyBetterFunc(5); // получим 10 x := MyBetterFunc(5,4); // получим 20

Оба вызова будут верными, просто в первом случае для второго параметра будет использовано значение, заданное по умолчанию.

Области видимости

Еще одной важной деталью, касающейся использования подпрограмм, является видимость переменных. Само понятие видимости подразумевает под собой тот факт, что переменная, объявленная в одном месте программы может быть доступна, или наоборот, недоступна, в другом. Прежде всего, это касается подпрограмм: как мы уже успели отметить, переменные, объявленные в заголовке процедур или функций, только в данной процедуре (функции) и будут доступны — на то они и называются локальными:

program Project1; procedure Proc1; var a: integer; begin a := 5; //верно. Локальная переменная a здесь видна end; begin a := 10; //Ошибка! Объявленная в процедуре Proc1 переменнаая здесь не видна end.

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

program Project2; var a: integer; // глобальная переменная a procedure Proc1; begin a := 5; // верно b := 10; // Ошибка! Переменая b на этот момент еще не объявлена end; var b: integer; // глобальная переменная b begin a := 10; // верно b := 5; // тоже верно. Здесь видны все г var a: integer; // глобальная переменная end.

Теперь рассмотрим такой вариант, когда у нас имеются 2 переменных с одним и тем же именем. Разумеется, компилятор еще на стадии проверки синтаксиса не допустит, чтобы в программе были объявлены одноименные переменные в рамках одного диапазона видимости (скажем, 2 глобальных переменных X, или 2 локальных переменных X в одной и той же подпрограмме). Речь в данном случае идет о том, что произойдет, если в одной и той же программе будет 2 переменных X, одна — глобальная, а другая — локальная (в какой-либо подпрограмме). Если с основным блоком программы все ясно — в нем будет присутствовать только глобальная X, то как быть с подпрограммой? В таком случае в действие вступает правило близости, т.е. какая переменная ближе (по структуре) к данному модулю, та и есть верная. Применительно к подпрограмме ближней оказывается локальная переменная X, и именно она будет задействована внутри подпрограммы.

program Project3; var X: integer; procedure Proc1; var X: integer; begin X := 5; // Здесь значение будет присвоено локальной переменной X end; begin X := 10; // Здесь же значение будет присвоено голобальной переменной X end.

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

program Project1; procedure Proc1; procedure SubProc; begin end; begin SubProc; // Верно. Вложенная процедура здесь видна. end; begin Proc1; // Верно. Процедура Proc1 объявлена в зоне глобальной видимости SubProc; // Ошибка! Процедура SubProc недоступна за пределами Proc1. end.

Наконец в том случае, когда имена встроенной и некой глобальной процедуры совпадают, то, по аналогии с переменными, в области видимости встроенной процедуры, именно она и будет выполнена.

Видимость в модулях

Все то, что мы уже рассмотрели, касалось программ, умещающихся в одном единственном файле. На практике же, особенно к тому моменту, когда мы перейдем к визуальному программированию, программы будут включать в себя множество файлов. В любом случае, программа на Object Pascal будет иметь уже изученный нами файл проекта — dpr, или основной модуль программы. Все прочие файлы будут располагаться в других файлах, или модулях (units), с типичным для Pascal расширением pas. При объединении модулей в единую программу возникает вопрос видимости переменных, а так же процедур и функций в различных модулях.

Для начала вернемся к рассмотрению структуры модуля, которая имеет ряд отличий от структуры программы. Итак, в простейшем случае, модуль состоит из названия, определяемого при помощи ключевого слова unit, и 2 секций — interface и implementation. Так вот как раз первая секция, interface, и служит для определения (декларации) типов данных, переменных, функций и процедур данного модуля, которые должны быть доступны за пределами данного модуля.

Чтобы лучше в этом разобраться, создадим программу, состоящую из 2 модулей — основного (dpr) и дополнительного (pas). Для этого сначала создайте новый проект типа Console Application, а затем добавьте к нему модуль, для чего из подменю File ‘ New выберите пункт Unit. После этого сохраните проект, щелкнув по кнопке Save All (или File ‘ Save All). Обратите внимание, что первым будет предложено сохранить не файл проекта, а как раз файл дополнительного модуля. Назовем его extunit.pas, а сам проект — miltiunits (см. Demo\Part1\Visibility). При этом вы увидите, что в части uses файла проекта произошло изменение: кроме постоянно добавляемого модуля SysUtils, появился еще один модуль — extunit, т.е. код стал таким:

uses SysUtils, extunit in ‘extunit.pas’;

Мы видим, что Delphi автоматически добавила пояснение, в каком файле находится подключаемый модуль. Это вызвано тем, что если о расположении собственных модулей Delphi все известно, то пользовательские модули могут находиться где угодно на жестком диске ПК. Но в данном случае мы сохранили и файл программы, и подключаемый модуль в одном каталоге, следовательно, их пути совпадают, и данное указание можно было бы опустить:

uses SysUtils, extunit;

Тем не менее, оставим код как есть, и приступим к разработке модуля extunit. В нем, в части implementation, напишем 2 процедуры — ExtProc1 и ExtProc2. Обе они будут делать одно и то же — выводить строку со своим названием. Например, для первой:

Теперь вернемся к главному модулю программы и попробуем обратиться к процедуре ExtProc1:

. begin ExtProc1; end.

Попытка компиляции или запуска такой программы приведет к ошибке компилятора «Undeclared identifier», что означает «неизвестный идентификатор». И действительно, одного лишь описания процедуры недостаточно, чтобы она была доступна вне своего модуля. Так что перейдем к редактированию extunit и в секции interface напишем строку:

Такая строка, помещенная в секцию interface, является объявлением процедуры ExtProc1, и делает ее видимой вне данного модуля. Отметим, что в секции interface допускается лишь объявлять процедуры, но не определять их (т.е. тело процедуры здесь будет неуместно). Еще одним полезным эффектом от объявления процедур является то, что таким образом можно обойти такое ограничение, как необходимость определения подпрограммы до ее вызова. Иначе говоря, поскольку в нашем файле уже есть 2 процедуры, ExtProc1и ExtProc2, причем они описаны именно в таком порядке — сначала ExtProc, а потом ExtProc2, то выведя объявление ExtProc2 в interface, мы сможем обращаться к ExtProc2 из ExtProc1, как это показано в листинге 6.5:

Листинг 6.5. Объявление процедур в модуле

unit extunit; interface procedure ExtProc1; procedure ExtProc2; implementation procedure ExtProc1; begin writeln(‘ExtProc1’); ExtProc2; // Если объявления не будет, то компилятор выдаст ошибку end; procedure ExtProc2; begin writeln(‘ExtProc2’); end; end.

Отметим, что теперь процедуры ExtProc2, так же, как и ExtProc1, будет видна не только по всему модулю extunit, но и во всех использующей этот модуль программе multiunits.

Разумеется, все, что было сказано о процедурах, верно и для функций. Кроме того, константы и переменные, объявленные в секции interface, так же будут видны как во всем теле модуля, так и вне него. Остается лишь рассмотреть вопрос пересечения имен, т.е. когда имя переменной (константы, процедуры, функции) в текущем модуле совпадает с таковым в подключенном модуле. В этом случае вновь вступает в силу правило «кто ближе, тот и прав», т.е. будет использоваться переменная из данного модуля. Например, если в extunit мы объявим типизированную константу Z, равную 100, а в multiunits — одноименную константу, равную 200, то обратившись к Z из модуля extunit, мы получим значение 100, а из multiunits — 200.

Если же нам в multiunits непременно понадобится именно та Z, которая находится в модуле extunit, то мы все-таки можем к ней обратиться, для чего нам пригодится точечная нотация. При этом в качестве имени объекта указывают название модуля:

Именно таким образом можно явно ссылаться на переменные, функции и процедуры, находящиеся в других модулях.

Некоторые стандартные функции

В Object Pascal, как уже отмечалось, имеются огромное количество стандартных процедур и функций, являющихся составной частью языка, и с некоторыми мы уже знакомы (например, приведенные в табл. 5.1 и 5.2 функции преобразования). Детальное описание всех имеющихся в Object Pascal процедур и функций можно получить в справочной системе Delphi, однако мы все-таки рассмотрим здесь некоторые из них, чтобы составить общее представление — см. таблицу 6.1.

Таблица 6.1. Некоторые стандартные процедуры и функции Delphi

Синтаксис Группа Модуль Описание
function Abs(X); арифметические System Возвращает абсолютное значение числа
procedure ChDir(const S: string); управления файлами System Изменяет текущий каталог
function Concat(s1 [, s2. sn]: string): string; строковые System Объединяет 2 и более строк в 1
function Copy(S; Index, Count: Integer): string; строковые System Возвращает часть строки
function Cos(X: Extended): Extended; тригонометрические System Вычисляет косинус угла
procedure Delete(var S: string; Index, Count: Integer); строковые System Удаляет часть строки
function Eof(var F): Boolean; ввод-вывод System Проверяет, достигнут ли конец файла
procedure Halt [ ( Exitcode: Integer) ]; управления System Инициирует досрочное прекращение программы
function High(X); диапазона System Возвращает максимальное значение из диапазона
procedure Insert(Source: string; var S: string; Index: Integer); строковые System Вставляет одну строку в другую
function Length(S): Integer; строковые System Возвращает длину строки или количество элементов массива
function Ln(X: Real): Real; арифметические System Возвращает натуральный логарифм числа (Ln(e) = 1)
function Low(X); диапазона System Возвращает минимальное значение из диапазона
procedure New(var P: Pointer); размещения памяти System Создает новую динамическую переменную и назначает указатель для нее
function ParamCount: Integer; командной строки System Возвращает количество параметров командной строки
function ParamStr(Index: Integer): string; командной строки System Возвращает указанный параметр из командной строки
function Pos(Substr: string; S: string): Integer; строковые System Ищет вхождение указанной подстроки в строку и возвращает порядковый номер первого совпавшего символа
procedure RmDir(const S: string); ввод-вывод System Удаляет указанный подкаталог (должен быть пустым)
function Slice(var A: array; Count: Integer): array; разные System Возвращает часть массива
function UpCase(Ch: Char): Char; символьные System Преобразует символ в верхний регистр
function LowerCase(const S: string): string; строковые SysUtils Преобразует ASCII-строку в нижний регистр
procedure Beep; разные SysUtils Инициирует системный сигнал
function CreateDir(const Dir: string): Boolean; управления файлами SysUtils Создает новый подкаталог
function CurrentYear: Word; даты и времени SysUtils Возвращает текущий год
function DeleteFile(const FileName: string): Boolean; управления файлами SysUtils Удаляет файл с диска
function ExtractFileExt(const FileName: string): string; имен файлов SysUtils Возвращает расширение файла
function FileExists(const FileName: string): Boolean; управления файлами SysUtils Проверяет файл на наличие
function IntToHex(Value: Integer; Digits: Integer): string; форматирования чисел SysUtils Возвращает целое в шестнадцатеричном представлении
function StrPCopy(Dest: PChar; const Source: string): PChar; строковые SysUtils Копирует Pascal-строку в C-строку (PChar)
function Trim(const S: string): string; строковые SysUtils Удаляет начальные и конечные пробелы в строке
function TryStrToInt(const S: string; out Value: Integer): Boolean; преобразования типов SysUtils Преобразует строку в целое
function ArcCos(const X: Extended): Extended; тригонометрические Math Вычисляет арккосинус угла
function Log2(const X: Extended): Extended; арифметические Math Возвращает логарифм по основанию 2
function Max(A,B: Integer): Integer; арифметические Math Возвращает большее из 2 чисел
function Min(A,B: Integer): Integer; арифметические Math Возвращает меньшее из 2 чисел

Те функции, которые имеются в модуле System, являются основными функциями языка, и для их использования не требуется подключать к программе какие-либо модули. Все остальные функции и процедуры можно назвать вспомогательными, и для их использования следует подключить тот или иной модуль, указав его в uses, например, как это делает Delphi уже при создании новой программы с SysUtils:

Что касается практического применения той или иной функции, то оно определяется, прежде всего, той группой, к которой данная функция относится. Например, арифметические функции используются для различных математических расчетов, строковые используются для манипуляций со строками и т.д. Разумеется, в каждой категории имеется множество других функций, помимо тех, что приведены в таблице 6.1, однако по ней можно получить общее представление о том, что есть в распоряжении Delphi-программиста.

Функции в действии

В целом мы уже ознакомились с несколькими десятками предопределенных процедур и функций, а так же умеем создавать собственные. Пора применить полученные знания на практике, для чего вновь вернемся к программе, рассмотренной в главе, посвященной операторам — игре «Угадай-ка». В ней, по сути, был реализован только один из рассмотренных в самом начале книги алгоритмов — угадывания числа. Что касается алгоритма управления, то на тот момент мы оставили его без внимания.

Но прежде, чем вносить в программу изменения, определимся с тем, что мы все-таки хотим получить в итоге. Допустим, что мы хотим сделать следующие вещи:

  1. Реализовать-таки возможность повторного прохождения игры без перезапуска программы;
  2. Добавить немного «геймплея». Иначе говоря, введем уровни сложности и подсчет очков. Новые уровни можно реализовать как повторное прохождение игры с увеличением сложности (скажем, за счет расширения диапазона загадываемых значений);
  3. В продолжение п. 2 добавить еще и таблицу рекордов, которая будет сохраняться на диске.

Поскольку часть работы уже выполнена, то для того, чтобы приступить к разработке новой версии игры (назовем ее «Угадай-ка 2.0»), мы не будем как обычно создавать новый консольный проект в Delphi, а откроем уже существующий (Ugadaika) и сохраним его под новым именем, скажем, Ugadaika2, и в новом каталоге. Таким образом, мы уже имеем часть исходного кода, отвечающую за угадывание, в частности, цикл while (см. листинг 4.5). Этот фрагмент логичнее всего выделить в отдельную процедуру, вернее даже функцию, которая будет возвращать число попыток, сделанное пользователем. Для этого создадим функцию, которая будет принимать в качестве аргумента число, которое следует угадать, а возвращаемым значением будет целое, соответствующее числу попыток. Ее объявление будет таким:

function GetAttempts(a: integer):integer;

Данная функция так же должна иметь в своем распоряжении переменную, необходимую для ввода пользователем своего варианта ответа. Еще одна переменная нужна для подсчета результата, т.е. количества попыток. В качестве первой можно было бы использовать глобальную переменную (b), однако во избежание накладок, для локального использования в функции следует использовать локальную же переменную. Что касается переменной-счетчика, то для нее как нельзя лучше подходит автоматическая переменная result. Еще одним изменением будет использование цикла repeat вместо while. Это вызвано тем, что с одной стороны, тем, что хотя бы 1 раз пользователь должен ввести число, т.е. условие можно проверять в конце цикла, а с другой мы можем избавиться от присвоения лишнего действия, а именно — присвоения заведомо ложного значения переменной b. Ну и еще одно дополнение — это второе условие выхода, а именно — ограничение на число попыток, которое мы установим при помощи константы MAXATTEMPTS:

const MAXATTEMPTS = 10;

В результате код функции получится таким, как представлено в листинге 6.6.

Листинг 6.6. Функция GetAttempts

function GetAttempts(a: integer):integer; var b: integer; begin Result:=0; repeat inc(Result); // увеличиваем счетчик числа попыток write(#13+#10+’?:’); read(b); if (b>a) then begin write(‘Too much!’); continue; end; if (b

Теперь, когда подготовительная работа сделана, можно браться за реализацию намеченных изменений. Прежде всего, в теле программы нам потребуется цикл, который как раз и будет обеспечивать логику исполнения программы. Для него нам так же понадобятся переменные. В частности, нужны счетчик цикла, устанавливающий текущий уровень сложности, так же нужны переменные для хранения набранных очков и числа попыток, и, кроме того, не помешает заранее определить файловую переменную для таблицы рекордов и строковую — для ввода имени «рекордсмена». Итого мы получаем следующий список переменных перед основным блоком программы:

var level, score, attempt: integer; f: TextFile; s: string;

Теперь инициализируем счетчик псевдослучайных чисел (т.е. оставим randomize на месте) и инициализируем нулем значения счета и уровня:

Наконец, напишем цикл для основного блока программы. Этот цикл должен быть выполнен хотя бы один раз и будет продолжать выполняться до тех пор, пока число попыток в последнем уровне было меньше максимально допустимого. В результате получаем цикл repeat со следующим условием:

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

repeat writeln(‘Level ‘+IntToStr(level)+’:’); writeln(‘From 0 to ‘+IntToStr(level*100)); attempt:=GetAttempts(random(level*100+1)); score:=score+(MAXATTEMPTS-attempt)*level; writeln(#10+’You current score is: ‘+IntToStr(score)); inc(level); until attempt>MAXATTEMPTS;

После завершения работы цикла, т.е. когда пользователь хоть раз истратит на отгадывание все 10 попыток, следует сообщить итоговый результат и сравнит его с предыдущим значением, которое следует считать из файла. Файл мы назовем records.txt, и сопоставим с переменной f:

Но прежде, чем попытаться что-либо прочитать из этого файла, необходимо убедиться, что такой файл уже есть, а если нет — то создать его, записав в него некий минимальный результат.

if not FileExists(‘record.txt’) then begin Rewrite(f); writeln(f,’0′); // первая строка содержит число-рекорд writeln(f,’None’); // а вторая — имя последнего победителя CloseFile(f); end;

Теперь можно считать этот файл. Правда, мы упустили из виду, что нам здесь тоже нужна переменная — для считывания предыдущего рекорда. В то же время, на данный момент мы уже имеем 2 ненужных для дальнейшей работы программы переменных — attempt и level, так что вполне можно воспользоваться любой из них для этих целей. Таким образом, мы получим следующий код:

Reset(f); readln(f, attempt); readln(f,s); writeln(#10+’BEST SCORE: ‘+IntToStr(attempt)+’ by ‘+s); CloseFile(f);

Ну и последнее, чего нам остается — это проверить, является ли новое значение выше рекорда, и если да — то записать новый рекорд в файл, не забыв спросить имя игрока:

Вот, собственно, и все. Полный код получившейся программы можно увидеть на листинге 6.7, или же в файле проекта в каталоге Demo\Part1\Ugadaika2.

Листинг 6.7. Программа угадай-ка, окончательный вариант

В завершение отметим, что эта программа использует использование не только функций, но и констант, глобальных и локальных переменных, а так же циклов и операций файлового ввода-вывода. Таким образом, на текущий момент мы познакомились со всеми основами обычного, процедурного программирования. Пора двигаться дальше — к объектно-ориентированному программированию в Object Pascal!

Илон Маск рекомендует:  Подвал веб-страницы
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL