Delphi.int.ru — Портал программистов

Вход Регистрация | Забыли пароль?

События

Сегодня:
Вопросы0    Ответы0    Мини-форумы0


Последние:
Вопрос12.02, 16:23 / #6648
Ответ20.02, 21:06 / #6648
Новости30 апреля 2012


Сейчас онлайн:
На сайте — 13
На IRC-канале — 3

Ссылки

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

Автор:
© Ерёмин А.А., 2009
Ничто так не засоряет постоянную память, как временные файлы.
Номер урока:
25

Введение

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

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

Для обычного пользователя, который не занимается программированием, знать о файлах и папках много не нужно. Достаточно иметь базовые представления, что это такое, как это используется, и какие возможны операции. Однако при программировании необходимо понимание того, что находится "внутри" и как всё это работает.
Итак, файл. Существуют сотни определений этого слова, но все они крутятся вокруг одно и того же. Файл (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. Создадим пустой текстовый файл.

var F: TextFile;
 
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.

Автор: Ерёмин А.А.

Статья добавлена: 3 февраля 2009

Следующая статья: Обучающий курс. 26. Записи (часть 2) »

Рейтинг статьи: 4.82 Голосов: 17 Ваша оценка:

Зарегистрируйтесь/авторизируйтесь,
чтобы оценивать статьи.


Статьи, похожие по тематике

 

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

Ссылка для форумов (BBCode):

Быстрая вставка ссылки на статью в сообщениях на сайте:
{{a:125}} (буква a — латинская) — только адрес статьи (URL);
{{статья:125}} — полноценная HTML-ссылка на статью (текст ссылки — название статьи).

Поделитесь ссылкой в социальных сетях:


Комментарии читателей к данной статье

Никонов Алексей
Репутация: нет

Никонов Алексей (5 октября 2011, 22:05):

Ну раз уж многие выкладывают свое дом. задание, то выложу и я =)

==================================================
procedure TForm1.Button1Click(Sender: TObject);
var f: TextFile;
i: Integer;
s: String; //s -- имя файла
begin
//--- Устанавливаем рабочий каталог
SetCurrentDir(Edit1.Text);
//--- Если тестовой папки не существует, создаем ее
if not DirectoryExists('test') then
MkDir('test');
//--- Устанавливаем новый рабочий каталог
SetCurrentDir(Edit1.Text + '\test');
//--- Присваиваем переменной "s" имя файла
s := Edit2.Text;
//--- Оставляем одно имя файла в переменной "s"
Delete(s,Pos('*',s),Length(s));
//--- Запускаем цикл
for i := SpinEdit1.Value to SpinEdit2.Value do
begin
//--- если файл существует тогда
if FileExists(s+IntToStr(i)+'.txt') then
begin
AssignFile(f,s+IntToStr(i)+'.txt');
Append(f);
Write(f,#13#10+ TimeToStr(Now)); //--- переносим на новую строку
CloseFile(f);
end
//--- если не существует то создаем и записываем дату
else
begin
AssignFile(f,s+IntToStr(i)+'.txt');
Rewrite(f);
Write(f,DateToStr(Now));
CloseFile(f);
end;

end;

end;
===============================================

Кстати, команды перехода по каталогам, создание папок и т.п. очень похожи на операторы в командной строке. Немного синтаксис другой только. Например SetCurrentDir('\'); -- как и к.стр. перебросит в корень диска.

Вообще, радует то, что все языки программирования похожи, например тот же javascript или С++. Правда Javascript как бы скриптовый язык, но принцип тот же.

Огромное спасибо за ваши уроки. Ждем продолжения с нетерпением! =)
Ерёмин А.А.
Репутация: +40

Ерёмин А.А. (30 марта 2011, 10:59):

Fomin S.S.: спасибо. Посмотрите следующий (26-ой) урок — там как раз про хранение записей в файлах. Неоднозначно вышло, конечно, что записи и файлы перемешались, но пока так.
Fomin S.S.
Репутация: нет

Fomin S.S. (30 марта 2011, 10:48):

"Ерёмин А.А. (10 августа 2009, 21:56):
Второй урок по этой теме будет, но его содержание пока не определено. Что именно интересует?"

А про типизированные файлы можно? :) Как работать с ними... общие методы/возможности сортировки в типизированных файлах...

У вас хорошо получается объяснять материал, на других сайтах я читал статьи по тип.файлам... - но мало что понял, не хватает подробностей, где-то просто на основе какой-то проги попытались объяснить суть - но видимо не оч удачно, там писали в консоле, а хотелось бы в объектном Паскале. :)
Ерёмин А.А.
Репутация: +40

Ерёмин А.А. (9 августа 2010, 22:41):

Цитата (antoca):

На самом деле, обычно бывает легче самому написать такое за 30 сек, чем сколько-то минут искать непонять что.

Бывает. А иногда и не бывает. Я бы не советовал выставлять свои рекомендации как единственно верные.

Цитата (antoca):

И обращаться вверх ../ - плохая идея.

Там же написано — ПРИМЕР. Людям, которые только учатся, нужно показать всё.
antoca
Репутация: +1

antoca (9 августа 2010, 20:04):

[quote]А Вы, уже было, приготовились открывать урок про работу со строками, и писать цикл по строке? :-) На самом деле, эта функция так и работает, но код уже написали давным-давно за нас[/quote]
На самом деле, обычно бывает легче самому написать такое за 30 сек, чем сколько-то минут искать непонять что.

И обращаться вверх ../ - плохая идея. Например, на хостинге (хоть речь и не об этом) такое обращение посчитают за взлом. В общем не делают так. Все равно что открывать коробку, не зная что в ней.
alexkrv
Репутация: нет

alexkrv (8 марта 2010, 20:27):

unit TextFilesF;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
UpDown1: TUpDown;
UpDown2: TUpDown;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

uses StrUtils;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var f: TextFile;
i: integer;
filename: string;
p: integer;
begin
for i := UpDown1.Position to UpDown2.Position do
begin
filename := Edit2.Text;
while Pos('*', filename) > 0 do
begin
p := Pos('*', filename);
Delete(filename, p, 1);
Insert(IntToStr(i), filename, p);
end;

if not DirectoryExists(Edit1.Text) then
begin
ShowMessage('Папка не существует');
break
end;

filename := Edit1.Text + filename;
AssignFile(f, filename);
if FileExists(filename) then
begin
Append(f);
WriteLn(f, TimeToStr(Now))
end
else
begin
Rewrite(f);
WriteLn(f, DateToStr(Now) + ' ' + TimeToStr(Now));
end;
CloseFile(f);
end;
end;

end.
Ерёмин А.А.
Репутация: +40

Ерёмин А.А. (10 августа 2009, 21:56):

Второй урок по этой теме будет, но его содержание пока не определено. Что именно интересует?
Насыров Павел
Репутация: +1

Насыров Павел (10 августа 2009, 20:01):

Молодец Автор
А рассматриватся API для работы с файлами будут ?
Beknur
Репутация: 0

Beknur (8 августа 2009, 08:31):

Просто супер. Жду продолжений
Тамара
Репутация: нет

Тамара (22 мая 2009, 20:17):

Да! Ждем продолжения!!!:))
nightly
Репутация: нет

nightly (2 мая 2009, 22:50):

Вот мое д/з)):


unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;

type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
UpDown1: TUpDown;
UpDown2: TUpDown;
Edit3: TEdit;
Edit4: TEdit;
Label1: TLabel;
Label2: TLabel;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation
{$R *.dfm}
function createF(a,s:string):string;
var f:textfile;
begin
assignfile(f,a+s);
if fileexists(a+s) then
begin
append(f);
write(f,timetostr(now)+' ');
end
else
begin
rewrite(f);
write(f,datetostr(now)+' '+timetostr(now)+' ');
end;
closefile(f);
end;

procedure TForm1.Button1Click(Sender: TObject);
var m:textfile;i,y:string;
j,k:integer;
begin
createdir(edit1.Text);
for j:=1 to length(edit2.Text) do
k:=pos('*',edit2.Text);
i:=edit1.text;
y:=edit2.Text;
delete(y,k,length(edit2.Text));
y:=y+edit3.text+'.txt';
for j:=strtoint(edit3.Text) to strtoint(edit4.Text) do
begin
createF(i,y);
delete(y,k,length(edit2.Text));
y:=y+inttostr(j+1)+'.txt';
end;
end;

end.
Сергей Викторович
Репутация: нет

Сергей Викторович (24 апреля 2009, 22:15):

Автор, я требую продолжения! Мне очень нравятся твои статьи. Из них я узнал очень много полезного для себя, чего не смог найти в других книгах. Короче, ты молодец!!!
Ерёмин А.А.
Репутация: +40

Ерёмин А.А. (11 апреля 2009, 19:37):

Работа со специализированными файлами к прямой работе с файлами не относится - для этого нужно использовать другие средства.
Rozin
Репутация: нет

Rozin (11 апреля 2009, 18:46):

Все понятно насчет каталогов и текстовых файлов, а как же быть с другими типами файлов. Как работать с файлами MS Office или графикой?
Тамара
Репутация: нет

Тамара (17 февраля 2009, 22:11):

Ну... мне удобней отматать всю прогу вверх и найти всё, что я наобъявляла здесь, чем мотатать 20 объявлений компонентов.. Но .. это ещё и атавизм от "начального образования":))
Ерёмин А.А.
Репутация: +40

Ерёмин А.А. (15 февраля 2009, 11:25):

Объявлять их там можно, но ни в одной "нормальной" программе в этом месте вы их не найдёте. Их объявляют ниже, после раздела type. В начало модуля листать приходится редко, а значит зачем туда помещать важные части программы? Процедуры можно либо привязывать к форме, либо просто помещать в разделе реализации выше того места, где они первый раз вызываются.
Относительно процедур рекомендую прочесть уроки №19 и №20.
Тамара
Репутация: нет

Тамара (14 февраля 2009, 21:15):

ЗЫ: сорри! я поняла задание, как создание двух файлов - первое число и второе. теперь догнала. Тогда цикл вызовов подпрограммы от первого - до второго числа.
Тамара
Репутация: нет

Тамара (14 февраля 2009, 21:13):

ну.. я так глобальные переменные объявляю и проседуры модульные... нельзя разве???
а где их объявлять???
Ерёмин А.А.
Репутация: +40

Ерёмин А.А. (12 февраля 2009, 23:59):

Что ж, вполне неплохо.

Смутили строки:
procedure zap_dan(n:string);
var m:string;
Каким чудом они попали в это место в начале модуля?

Да, и ещё: имелось ввиду, что если введены числа 1 и 5, то будет создано 5 файлов: 1.txt, 2.txt, ..., 5.txt.
Тамара
Репутация: нет

Тамара (11 февраля 2009, 20:49):

unit zadachka;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, Spin, ExtCtrls;
procedure zap_dan(n:string);
var m:string;
type
TForm1 = class(TForm)
Panel1: TPanel;
Edit1: TEdit;
Edit2: TEdit;
SpinEdit1: TSpinEdit;
SpinEdit2: TSpinEdit;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
procedure FormShow(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
procedure BitBtn2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure zap_dan(n: string);
var s: textfile;
z: string;
begin
assignfile(s, getcurrentdir()+ 'папка\'+n +'.txt');
if fileexists(getcurrentdir()+ '\папка\'+n +'.txt') then
begin
append(s);
write(s, timetostr(now)+' ');
end else
begin
rewrite(s);
write(s,datetostr(now)+' '+timetostr(now)+ ' ');
end;
closefile(s);
end;

procedure TForm1.FormShow(Sender: TObject);
begin
edit1.Text:= getcurrentdir()+ '\папка';
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
var a, b: integer;
begin
a:= spinedit1.Value;
b:= spinedit2.Value;
edit2.Clear;
edit2.Text:= (inttostr(a)+ ' ' +inttostr(b));
zap_dan(inttostr(a));
zap_dan(inttostr(b));
end;

procedure TForm1.BitBtn2Click(Sender: TObject);
begin
form1.Close;
end;

end.;):)
Ерёмин А.А.
Репутация: +40

Ерёмин А.А. (5 февраля 2009, 20:03):

Хорошо, задачи будут, раз читатели просят :-) Для этого урока предлагаю такое задание.

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

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

Тамара (5 февраля 2009, 19:15):

Куда исчезли задачки и ДЗ? Пожалуйста, верните!!

Оставлять комментарии к статьям могут только зарегистрированные пользователи.