Delphi прописать путь к файлу doc и открыть его
← →
ossa ( 2003-09-04 07:57 ) [0]
Environment options, где и что нужно писать, т.е. я хочу добавить новый компонент, открыл ее из оболочки дельфи, запустил
инстал, вывелось окошка что компоненты инсталированы в папке BPL
теперь нужно в енвиромент обшионс указать и прописать, вот тут
я незнаю где, как и что писать, подскажите пожалуйста
KSergey ( 2003-09-04 08:04 ) [1]
Environment options|Library
Library Patch - добавить путь к DCU-шкам нового компонента
Browsing Patch - добавить путь к PAS нового компонента
В Browsing Patch - не обязательно. Каюсь, и сам тут маненько не до конца секу.
← →ossa ( 2003-09-04 08:15 ) [2]
а вот там существует уже пути, мне нужно как добавить к ним
и как это делаеться, к примеру в Browsing Patch нужно удалить предыдущее значение, и что обозначает "$"
Palladin ( 2003-09-04 08:17 ) [3]
Library также и к pas
← →KSergey ( 2003-09-04 08:27 ) [4]
> [3] Palladin © (04.09.03 08:17)
> Library также и к pas
А Browsing Patch - это для чего? Будьте добры для меня, темного.
> [2] ossa (04.09.03 08:15)
> а вот там существует уже пути, мне нужно как добавить к
> ним
> и как это делаеться, к примеру в Browsing Patch нужно удалить
> предыдущее значение, и что обозначает "$"
Вы кнопочки нажимать умеете? Ворд изучали методом найчного тыка7 Я - да. Ну так и тут - попробуйте понажимать всякие кнопочки рядом :) (там есть такая кнопочка с 3-мя точками, разобраться как добавлять - 5 минут)
$(DELPHI) - это путь до дельфи. Им так прикольнее показалось.
← →Palladin ( 2003-09-04 08:29 ) [5]
> KSergey © (04.09.03 08:27) [4]
Нэповеришь. Все пути к нужным pas и dcu выставлены в Library path. Browsing path как было по умолчанию при установке так и стоит. И все работает и все компилится :) Попробуй.
Palladin ( 2003-09-04 08:31 ) [6]
Ну все верно. Почитай справку, там так и написано "Specifies search paths where compiler can find the source files for the package.",
Browsing Path нужен для Project Browser.
KSergey ( 2003-09-04 08:49 ) [7]
[5] Palladin © (04.09.03 08:29)
Нэповеришь. Все пути к нужным pas и dcu выставлены в Library path. Browsing path как было по умолчанию при установке так и стоит. И все работает и все компилится :) Попробуй.
Да я и не спорю, у самого так. Мне было инетерсно просто зафиг бровзинг нужно. Теперь еще почитаю про прожект бровзер - и, надеюсь, пойму до конца ;)
← →KSergey ( 2003-09-04 08:50 ) [8]
Впрочем, тогда, конечно, это идет в разрез с моим первым постом [1] KSergey (04.09.03 08:04)
Признаю, я там нагло врал.
Когда речь идет о работе программы с текстовым файлом, подразумеваются процедуры ввода данных из файла в программу или, наоборот, запись этих данных в файл программой. Для текстового файла допустима простая работа с файлом без особых дополнительных механизмов, которые применяются для работы со специализированными файлами, такими как при загрузке данных из Excel или работе программы с базой данных. Разумеется, Delphi располагает возможностями работать с файлами с использованием компонентов. Но в данной статье рассматривается механизм прямой работы с текстовым файлом без использования дополнительных компонентов.
Итак, в общем виде, работа с файлом заключается в следующих этапах:
1. подключение к файлу – связь с внешним файлом, указание режима подключения;
2. выполнение операций записи в файл или чтения из файла;
3. завершение работы с файлом.
Операции с файлами
Для чтения из файла, необходимо назначить режим чтения и использовать команду Readln(), которая будет вводить в строковую переменную по одной строке из файла. Затем с этой переменой можно выполнить необходимые действия.
Обычно для загрузки всех строк из файла используется оператор цикла. Для того, чтобы определить, что файл закончился используется функция EOF() (End Of File). Таким образом получается цикл, в котором последовательно в строковую переменную вводятся все строки файла и завершающийся после окончания фала:
Для записи, назначение режим записи в файл и командой Writeln() производится запись по строкам.
Не используйте относительные имена файлов
Доступ к файлу можно получить по абсолютному или относительному имени (пути).
Абсолютное ("полностью квалифицированное") имя начинается с имени диска или сервера и указывает все компоненты пути, например: " C:\Projects\TestProject\Data.txt " или " \\SERVER\Projects\TestProject\Data.txt ". Такое имя всегда однозначно указывает на файл - вне зависимости от любых внешних факторов.
Относительное имя содержит не все компоненты пути и указывает файл относительно другого каталога, имя которого в самом имени не указано, например: " Data.txt " или " ..\Data.txt ". Для определения точного положения файла недостаточно одного относительного имени, необходимо ещё имя каталога, относительно которого будет трактоваться это имя. Поэтому один и тот же относительный путь может ссылаться на разные файлы. К примеру, путь " Data.txt " ссылается на C:\Projects\TestProject\Data.txt , если текущий каталог (или каталог, относительно которого происходит разрешение имени) равен C:\Projects\TestProject , но этот же путь будет ссылаться на C:\Windows\Data.txt , если текущий каталог - C:\Windows .
Подробнее о файловых именах можно почитать здесь.
Здесь же, в этой статье, я хочу показать, что вам никогда не нужно использовать относительные имена файлов.
Очень часто начинающие программисты используют относительные пути к файлам для работы с файлами внутри папки своей программы, например:
Что не так с этим кодом?
Начинающий программист считает, что имя " input.txt " будет вычисляться относительно пути к его программе. Иными словами, если программа (.exe-файл) лежит в " C:\Projects\TestProject ", то, указав " input.txt " в Assign , мы откроем файл " C:\Projects\TestProject\input.txt ". Это попросту неверно!
- Для начала, текущий каталог при старте вашей программы задаётся не вами, а вызывающим вас процессом. Все функции запуска программы имеют строковый параметр для передачи туда имени каталога, который станет текущим для запускаемой программы. И вызывающая вас программа может передать туда всё, что угодно. Это может быть папка с вашей программой, да. Но это может быть и любая другая папка;
- Далее, к примеру, если ваша программа запускается через ярлык на рабочем столе или ярлык в меню Пуск / Программы, то текущий каталог для вашей программы указан в свойствах ярлыка. Например, сама Delphi запускается с текущим каталогом = папке с проектами (например, C:\Program Files\Borland\Delphi 7\Projects\ или даже просто C:\Projects\ ) - что, очевидно, не равно папке с программой ( C:\Program Files\Borland\Delphi 7\Bin\ );
- А если вы пишете программу, которая открывает файлы какого-то типа, то вы, вероятно, назначите свою программу для открытия таких файлов (ассоциируете тип файлов в вашей программой). Но когда пользователь дважды-щёлкнет по такому файлу, ваша программа запустится с текущим каталогом равным каталогу открываемого файла. Т.е. текущий каталог будет C:\Documents , а не C:\Projects\TestProject ;
- А если вы пишете код для службы (Win32 Service), то текущий каталог будет C:\Windows\System32 .
P.S. Кроме того, размещение файлов с данными/конфигурацией в папке с программой - крайне плохая идея, если только вы не пишете портативную (portable) программу (см. также).
Далее, есть же такие функции как GetCurrentDir и (что интереснее) SetCurrentDir . "Set" решительным образом намекает на то, что текущий каталог - вещь не фиксированная и его можно менять. Иными словами, текущий каталог не только может быть не равен каталогу программы, но и вообще может меняться в процессе выполнения программы! Действительно:
Конечно, тот факт, что текущий каталог можно менять, сам по себе ещё не означает проблему. Но посмотрите на такой код:
Что случилось? Дело в том, что внешний код (а именно - код диалога открытия файла) поменял текущий каталог. Ваш код оказался не готов к этому.
P.S. Почему вообще диалог открытия файла меняет текущий каталог? Потому что вы (= прикладные программисты) пишете код с использованием относительных имён файлов.
Иными словами, проблема состоит в том, что кто угодно может менять текущий каталог в любой момент времени. Даже если в вашем коде нет вызовов другого внешнего кода, который меняет текущий каталог, всё равно текущий каталог может быть изменён другим потоком в вашей программе. Даже если вы сами не создаёте других потоков, потоки могут быть созданы DLL, которые загружены в вашу программу. Помимо системных DLL, это могут быть DLL от любых оконных ловушек, расширителей оболочек и даже антивирусов.
Вывод? Код, который адресует файл относительным именем работает благодаря случайности, а именно: благодаря тому, что никакой другой код не изменил текущий каталог перед тем, как вы вызвали функцию доступа к файлу, передав ей относительное имя файла.
Прежде чем мы посмотрим на правильное решение, давайте сделаем обзор того, чего делать не нужно.
Многие либо первым действием в программе, либо непосредственно перед выполнением участка кода с использованием относительных имён явно меняют текущий каталог на каталог программы. Например:
Или же сохраняют/восстанавливают текущий каталог перед вызовом кода, который потенциально может менять текущий каталог, например:
Что не так с этими решениями?
Во-первых, текущий каталог, являясь глобальной переменной, может быть изменён другим потоком как раз между вызовами SetCurrentDir и Assign . Если этого не происходит, то ваш (некорректный) код работает благодаря случайности (случайность состоит в том, что этого не произошло).
Во-вторых, если вы форсированно устанавливаете свой текущий каталог, отбрасывая каталог, заданный вам вызывающим, вы можете открыть не тот файл! Например, пусть вы пишете программу-конвертер, пусть она конвертирует картинки из формата .jpg в формат .jpg, пусть вашу программу можно вызвать, передав ей имя файла в командной строке. Тогда пользователь может вызвать вас так:
(здесь C:\Documents> является приглашением командной строки, а "C:\Converter\convert.exe" "holidays.jpg" - непосредственно командной строкой).
Т.е. пользователь открыл консоль, он находится в папке C:\Documents и вызывает вас ( convert.exe ) из папки C:\Converter , передавая вам имя файла ( holidays.jpg ) параметром командной строки.
(Почти аналогичная ситуация будет если пользователь дважды-щёлкнет по файлу holidays.jpg в открытой папке C:\Documents в Проводнике - при условии, что ваша программа ассоциирована с .jpg файлами).
В этом случае ваша программа ( convert.exe ) запустится из папки C:\Converter , но текущим каталогом для неё будет C:\Documents . Если вы форсированно смените текущий каталог на папку с программой ( C:\Converter ), то не сможете открыть файл holidays.jpg , поскольку он находится в папке C:\Documents , а не C:\Converter .
В-третьих, если вы передаёте имена файлов между процессами, то текущий каталог в вашей программе никак не связан с текущим каталогом в программе, с которой вы общаетесь. Например, самый типичный случай: пусть вы пишете просмотрщик файлов, ваша программа ограничена одним экземпляром. Если вас запускают на просмотр файла, вы проверяете, не открыты ли вы уже, если да - то вы передаёте в первый экземпляр имя файла и выходите.
Имя файла вам могли передать в относительном формате (к примеру, вызвали вас из командной строки). Вы передали это имя "как есть" в первую копию своей программы. Однако текущий каталог первой копии равен неизвестно чему, он не равен текущему каталогу вашей второй копии. Как бы вы не меняли текущий каталог в первой копии программы перед попыткой доступа к файлу, который вам передали, вы никак не можете знать, каким же был текущий каталог в другой программе (вашей второй копии). И снова, ваш код, оперирующий относительными путями файлов, будет работать только благодаря случайности (в этом случае случайность состоит в том, что текущий каталог оказался одинаков в обоих экземплярах вашей программы).
Более того, когда вы меняете текущий каталог на какой-то - этот каталог открывается вашей программой. В частности, это означает, что вы не можете удалить этот каталог.
Зачем же вообще относительные пути, если они так плохи?
Ну, относительные пути нужны для человека-оператора. Они экономят время на набор текста. Действительно, вместо того, чтобы вводить длинный путь вида C:\Documents and Settings\Admin\Documents\Data from 2014\March.doc - вы можете ввести просто March.doc (конечно же, при условии, что вы "находитесь" в каталоге C:\Documents and Settings\Admin\Documents\Data from 2014\ ).
Из вышесказанного напрямую следует правильное решение. Раз относительные имена предназначены для человека, то вам (вашему коду) не следует их использовать. Всё, что вы можете сделать с относительным именем - перевести его в абсолютное. И оперировать в дальнейшем только абсолютным именем файла.
- Развернуть переменные окружения;
- Преобразовать относительное имя в абсолютное;
- Канонизировать путь, свернув '.', '..' и лишние разделители каталогов;
- Преобразовать короткий путь в длинный.
- Каждый раз, когда вы получаете имя файла из внешнего источника (командной строки, конфигурации, диалога и т.п.) - сохраняйте его в переменную с суффиксом Unsafe . Например, DocumentFileNameUnsafe := ParamStr(1) ;
- Не передавайте переменные с суффиксом Unsafe в функции открытия файлов;
- Не передавайте переменные с суффиксом Unsafe в другие программы (через IPC, командную строку и т.п.);
- Вы можете сохранять переменные с суффиксом Unsafe в файл конфигурации;
- Передайте переменную с суффиксом Unsafe в функцию нормализации и сохраните результат в переменной без суффикса Unsafe . Например, DocumentFileName := PathSearchAndQualify(DocumentFileNameUnsafe) ;
- Вы можете передавать переменные без суффикса Unsafe в функции открытия файлов и другие программы (IPC, командная строка и т.п.);
- Если вам точно известно имя файла (оно задано константой в коде) и вы знаете папку, в которой лежит файл (не обязательно константа, но хотя бы логическое размещение вида "каталог программы", "подкаталог ABC папки Application Data"), то получите путь к каталогу, затем добавьте к нему имя файла и сохраните результат в переменную без суффикса Unsafe . Если имя файла, заданное в константе, содержит '.' или '..' - выполните нормализацию перед сохранением в переменную;
- Измените текущий каталог на, скажем, C:\Windows\System32 (разумеется, путь надо задавать не константой, а получать через GetSystemDirectory ) сразу после того, как вы нормализовали все имена файлов из параметров командной строки;
- Если вы запускаете внешнюю программу, передавая ей имя файла для открытия, то задайте текущий каталог для запускаемой программы равным каталогу, содержащему открываемый файл (даже хотя вы передаёте полное имя файла);
- Используйте суффикс Dir для переменных и функций, которые хранят/возвращают путь (к каталогу) без ведомого разделителя (например, 'C:\Windows'). Используйте суффикс Path для переменных и функций, которые хранят/возвращают путь с ведомым разделителем (например, 'C:\Windows\'). Избегайте использования переменных и функций, для которых вы не знаете, будет ли в конце пути разделитель. Преобразуйте такие переменные и функции в Dir или Path с помощью ExcludeTrailingPathDelimiter и IncludeTrailingPathDelimiter соответственно, например: CurrentPath := IncludeTrailingPathDelimiter(GetCurrentFolder) . Эта семантика с Dir / Path защитит вас от неверных результатов вида ExtractFileDir(. ) + 'input.txt' = 'C:\Programinput.txt' или ExtractFilePath(. ) + '\input.txt' = 'C:\Program\\input.txt' .
- Старайтесь хранить имена каталогов с ведущим разделителем, а имена файлов - без разделителя. Например, 'C:\Windows\', но 'C:\Windows\notepad.exe';
- Если вы работаете в Unicode-версии Delphi (Delphi 2009 и выше) и хотите передать имя файла во внешний код (программу или DLL) - преобразуйте имя файла в короткое имя файла ( PathGetShortPath - см. ниже). Это увеличит шансы правильного открытия файла, если вызываемый код не поддерживает Unicode или неверно обрабатывает пробелы;
- Если вы передаёте имя файла по IPC - всегда предпочитайте Unicode-форму (используйте WideString ).
- Проведите нормализацию имён файлов, как указано в алгоритме выше, сохранив их в переменные без суффикса Unsafe ;
- Получите каталог, относительно которого вам нужно сохранять пути (каталог с программой, каталог с корневым файлом документа и т.п.). Нормализуйте его и сохраните в переменную без суффикса Unsafe ;
- Получите относительный путь для вашего пути файла из п1 относительно каталога из п2 с помощью функции PathGetRelativePath (см. ниже раздел практики). Сохраните результат в переменную с префиксом Unsafe ;
- Запишите переменную из п3 в вашу конфигурацию или документ.
Давайте посмотрим, как эти рекомендации нужно делать на примерах.
Подключение к файлу
Для связи программы с файлом используется специальная переменная – "Файловая переменная". Объявляется она так же как и любая переменная в Delphi. Тип это переменной может быть File для типизированных (хранящих данные определенного типа) файлов, а можно указать TextFile, что будет означать тип обычного текстового файла. Объявление переменной:
В исполняемом коде программы выполняется подключение к внешнему файлу:
Команда AssignFile, выполняет связь файловой переменной с внешним файлом. Вторым параметром указывается адрес файла. Он может быть задан относительным или абсолютным. Если указать только имя файла, то программа будет пытаться обнаружить его в той же директории, где она сама и находится. Абсолютный путь указывается от корневого диска:
Использование относительной директории дает возможность не привязываться к конкретным дискам и адресам. Например:
После того как выполнено подключение, выполняется процедура, устанавливающая режим работы с файлом. В основном это режим чтения или записи. Эти режимы назначаются процедурами Reset() ( для чтения) и rewrite() (для записи):
* Для команды Rewrite() следует учитывать, что при ее выполнении, она либо создает файл, указанный в файловой переменной, либо если он уже есть перезаписывает файл заново, удаляя старый без какого-то предупреждения.
Любую из указанных команд можно использовать без команды AssignFile(). Для этого достаточно вторым параметром указать путь к файлу. Таким образом, она сразу выполнит привязку файла к файловой переменной и назначит режим работы с этим файлом:
Примеры работы с текстовыми файлами в Delphi
Чтение в переменную одного значения из файла:
Загрузить все строки файла в компонент Memo:
Следует отметить, что для этой задачи проще воспользоваться командой самого компонента Memo LoadFromFile().
Записать строку в файл:
Записать в текстовый файл все строки из компонента Memo:
Как и для чтения из файла в Memo, так и здесь, имеется специальная команда:
. when altering one's mind becomes as easy as programming a computer, what does it mean to be human.
Примеры кода
Открываем файл в известной папке
Неправильный код:
А вот правильный вариант этого кода: или: Где GetApplicationDataPath - ваша функция получения пути к папке Application Data (подробнее).
Читаем имя файла из командной строки
Неправильный код:
А вот правильный вариант этого кода: Здесь OpenDocument - какая-то ваша функция открытия файла (например, загрузить .jpg файл и показать его на форме). Предполагается, что вы вызовете ProcessCommandLine при запуске программы, например:
(в примере выше ProcessCommandLine удобно сделать методом главной формы)
Просмотрщик: передаём имя файла в первый экземпляр программы
Неправильный код:
А вот правильный вариант этого кода: Здесь PassFileToFirstInstance - ваша функция, которая проверяет, запущена ли уже ваша программа, и если да, то передаёт ей имя файла. Она может выглядеть как-то так (показаны фрагменты):
Удивительно, но факт — запрос «delphi файлы» в Яндексе — это один из самых популярных запросов, касающихся Delphi. Популярнее только «delphi скачать» — видимо ещё не все слышали про такую штуку как Delphi Community Edition. Раз есть в Сети запрос — должен быть и ответ. Посмотрим, что получится в итоге.
Содержание статьи
Классика работы с файлами в Delphi — ключевое слово File
Этот способ, без преувеличения, можно назвать древнейшим способом работы с файлами в Pascal/Delphi. Однако и он до сих пор используется в работе, особенно, если это, например, лабораторная работа по информатике в школе или ВУЗе.
Для определения файловой переменной в Delphi/Pascal используется ключевое слово File. При этом, мы можем определить как типизированный файл, так и не типизированный, например:
Для типизированного фала мы можем задать тип данных фиксированного размера (ShortString, String[20], Integer, Single и так далее), например, мы можем определить такие типизированные файлы:
Или, как в примере выше использовать для указания типа запись (record), в которой все поля имеют фиксированный размер. Для типизированного файла нельзя указывать типы данных, размер которых не фиксирован, например, вот такие определения файловых переменных недопустимы:
Более того, даже компилятор Delphi укажет вам на ошибку, сообщив следующее:
Определив файловую переменную можно приступать к работе с файлом. Алгоритм работы при этом будет следующим:
- Ассоциировать файловую переменную с файлом на диске
- Открыть файл
- Записать/Прочитать файл
- Закрыть файл
При этом, для типизированных и не типизированных файлов работа в части чтения/записи несколько различается в плане используемых методов.
Работа с типизированными файлами в Delphi
Рассмотрим несколько примеров работы с типизированными файлами в Delphi.
Для начала, рассмотрим вариант работы с типизированным файлом, например, представленном выше:
Пример №1. Запись данных в типизированный файл Delphi
Запишем в наш файл две записи:
Рассмотрим методы, используемые в этом примере:
Связывает файловую переменную F с внешним файлом FileName. В качестве второго параметра может задаваться как абсолютный путь к файлу, например, ‘C:/MyFile.txt‘, так и относительный, например, в коде выше файл будет создан рядом с exe-файлом.
Создает новый файл и открывает его. Если внешний файл с таким именем уже существует, он удаляется и на его месте создается новый пустой файл. Если F уже открыт, он сначала закрывается, а затем воссоздается. Текущая позиция файла устанавливается в начале пустого файла.
F — это переменная, связанная с внешним файлом с использованием AssignFile. RecSize — это необязательное выражение, которое можно указывать, только если F является нетипизированным файлом (об этом ниже).
Используется для записи в типизированный файл. F — файловая переменная, P1..PN — это переменная того же типа, что и тип файла F.
Прекращает связь между файловой переменной и файлом внешнего диска. F — это файловая переменная любого типа. Внешний файл, связанный с F, полностью обновляется, а затем закрывается, освобождая дескриптор файла для повторного использования.
В результате выполнения представленного выше кода, рядом с exe-файлом будет создан новый файл MyFile.txt, содержащий две записи, при этом, каждая запись будет иметь фиксированный размер, вне зависимости от фактических имени/фамилии.
Для того, чтобы в delphi не перезаписывать каждый раз файл, а добавлять в конец файла новые записи необходимо открывать типизированные файлы методом Reset. Рассмотрим пример добавления новых записей в типизированные файлы Delphi.
Пример №2. Добавление записей в типизированный файл Delphi
Рассмотрим такой пример Delphi:
Разберемся с тем, что здесь делается. Во-первых, условие:
проверяет, существует ли файл на диске. Метод FileExist имеет следующее описание:
FileName — имя файла, существование которого необходимо проверить. Второй параметр — FollowLink учитывается только при использовании символической ссылки. То есть, если нужно проверить только наличие символической ссылки на файл, то параметр FollowLink устанавливается в False, а если нужно проверить наличие и символической ссылки на файл и самого файла, то FollowLink устанавливается в True (значение по умолчанию).
Таким образом, в нашем примере, если файла нет на диске то он создается пустым. Далее выполняется цикл:
В этом цикле, если пользователь вводит 1, выполняется процедура AppendTypedFile, которая добавляет в файл очередную запись:
Здесь, в принципе, весь алгоритм расписан в комментариях к процедуре.
Метод Reset не воссоздает файл снова, как Rewrite, а открывает его для чтения/записи (в случае двоичных файлов). Что касается метода Seek, то он имеет следующее описание:
F — файловая переменная, ассоциированная с файлом на диске, N — номер записи в файле (первый номер — 0). Чтобы переместиться сразу в конец файла, мы сделали такой вызов:
где FileSize — это метод Delphi имеющий следующее описание:
В случае использования типизированных файлов эта функция возвращает количество записей в файле.
После того, как пользователь вводит что-то кроме 1 срабатывает метод ReadTypedFile — чтение всех записей из файла:
Здесь мы, опять же, открываем файл методом Reset и в цикле while..do проходим по всем записям файла, пока не дойдем до конца. Здесь мы использовали два новых метода Delphi:
Eof возвращает True, если текущая позиция файла находится за последним символом файла или файл пуст. В противном случае Eof возвращает False.
По аналогии с методом Write, метод Read производит чтение очередной записи из файла и имеет следующее описание:
Результат работы нашего примера может быть следующим:
Ещё одним полезным методом для работы с типизированными файлами может быть процедура Truncate:
Удаляет все записи после текущей позиции файла. Вызовите Truncate в коде Delphi, чтобы текущая позиция файла стала концом файла (Eof (F) вернет true).
Рассмотрим пример использования этой процедуры.
Пример №3. Удаление последних записей типизированного файла в Delphi
Воспользуемся файлом, созданным в предыдущем примере и удалим из него две последние записи:
В этом примере мы делаем следующее:
- Открываем файл существующий AssignFile/Reset
- Определяем количество записей в файле (Count:=FileSize(TypedFile))
- Если количество записей меньше двух, то спрашиваем у пользователя стереть ли все записи и, в случае положительного ответа, вызываем метод Tuncate
- Если количество записей в файле больше двух, то смещаемся на нужную нам позицию в файле (Seek(TypedFile, Count-2)) и затираем две последние записи методом Truncate.
Подведем итог
Для работы с типизированными файлами в Delphi в самом общем случае нам необходимо выполнить следующую последовательность операций:
- Определить тип записей в файле — это могут быть стандартные типы данных Delphi с фиксированным размером: ShortString, integer, single и так далее или собственные типы данных, например, записи (record), но, в этом случае, главное условие — размер записи должен быть фиксированным.
- В коде Delphi/Pascal определить файловую переменную, используя ключевое слово fileи, указав тип записей файла, определенный в пункте 1.
- Ассоциировать файловую переменную с внешним файлом на диске, используя метод AssignFile.
- Открыть файл для чтения/записи, используя методы Rewrite/Reset.
- Чтобы сделать в файл очередную запись используем метод Write, для чтения очередной записи из файла — используем метод Read.
- Закрыть файл методом CloseFile.
В целом, рассмотренные выше примеры не охватывают всех возможностей работы с типизированными файлами в Delphi, а, скорее, показывают основные операции по работе с типизированными файлами. Поэтому ниже представлен перечень методов которые могут применяться при работе с типизированными файлами в Delphi/Pascal.
Функции и процедуры для работы с типизированными файлами в Delphi/Pascal
Сегодня, в последний рабочий день недели, практически весь день провозился над передачей данных из Delphi в Word. Так как подозрение есть, что работа продолжится то решил кое-какие моменты по работе с Microsoft Word в Delphi запечатлеть и у себя в блоге. Написать такую мини-шпаргалку (тем более, что по Excel уже кое что есть).
Для начала, немного общих моментов по работе с MS Office в Delphi. И первое, что мы сделаем — это создадим объект Word.Application. Создается этот объект абсолютно также, как и объект Excel.Application:
Всё достаточно просто. Далее мы можем работать с объектом следующим образом:
- Создавать документ Word с нуля
- Открыть уже существующий документ и изменить в нем текст для получения необходимой формы документа.
Рассмотрим оба варианта, т.к. оба они имеют как свои плюсы, так и недостатки.
1. Создание документа Microsoft Word в Delphi с нуля.
Чтобы создать новый документ необходимо выполнить метод Add у коллекции Documents, т.е.:
и после этой операции уже начинать работать с документам обращаясь к нему по индексу или имени в коллекции. Также, можно создать новый документ по шаблону (*.dot). Для этого необходимо выполнить тот же метод Add, но с одним входным параметром — путем к файлу-шаблону:
Чтобы получить список всех открытых в данный момент документов Word можно воспользоваться следующим листингом:
Обратите внимание, что нумерация начинается с 1, а не с нуля. Чтобы активировать любой документ из коллекции для работы, необходимо выполнить метод Activate:
где index — номер документа в коллекции.
Теперь можно приступать к записи и чтению документа. Для работы с текстов в документе Word, как и в Excel для работы с ячейками таблицы, определен объект Range. Именно методы этого объекта и дают нам возможность работы с текстом. Для начала рассмотрим работу двух основных методов: InsertBefore и InsertAfter.
Как следует из название — первый метод вставляет текст в начало содержимого Range, а второй — в конец. При этом сам объект Range может содержать как весть документ (Document) так и какую-либо его часть. Например, в следующем листинге я вставлю строку в начало документа и затем методом InsertAfter буду добавлять несколько строк текста в конец документа:
При выполнении этих трех операции Range содержал весь документ.
Если работать со всем документом неудобно, а необходимо, например выделить фрагмент с 50 по 100 символ и работать с ним, то можно воспользоваться функцией Range, которая вернет нам необходимый объект Range:
Это что касается записи текста. Решение обратной задачи — чтения текста из документа ещё проще. Достаточно воспользоваться свойством Text у объекта Range:
Также для чтения документа можно воспользоваться коллекцией документа Words (слова). За слово принимается непрерывный набор символов — цифр и букв, который оканчивается пробелом.
Перечисляются слова документа точно также как и при работе с коллекцией документов, т.е. первое слово имеет индекс 1 последнее — Word.Count.
В данном случае я вывел на экран последнее слово в документе.
Очевидно, что приведенный выше способ работы с документам хорош в случае, когда требуется создать относительно простой документ Word и не требуется лишний раз рассчитывать фрагменты текста, правильно вставлять таблицы и т.д. Если же необходимо работать с документами, которые имеют сложное содержание, например текст в перемежку с рисунками, таблицами, а сам текст выводится различными шрифтами, то, на мой взгляд наиболее удобно использовать второй способ работы с Word в Delphi — просто заменить текст в уже заранее заготовленном документа.
Реализация: голая Delphi
Во-первых, даже в Delphi "из коробки" есть несколько подходящих функций (некоторые функции могут отсутствовать в старых версиях Delphi):
Закрытие файла
По завершении работы с файлами, особенно в случае записи в них данных, необходимо корректно завершить работу с файловой переменной. Это делается для того, чтобы сохранить все внесенные в файл изменения.
15 января 2015 г.
2. Работа с документами Word в Delphi. Открытие готового документа и замена текста.
Чтобы открыть заранее заготовленный документ Word в Delphi достаточно воспользоваться методом Open у коллекции Documents, например так:
Метод Open можно вызывать с несколькими аргументами:
- FileName: string — путь и имя файла;
- ConfirmConversions: boolean — False — не открывать диалоговое окно «Преобразование файла» при открытии файла, формат которого не соответствует формату Word (doc или docx)
- ReadOnly:boolean — True — открыть документ в режиме «Только для чтения»
- AddToRecentFiles: boolean — True, чтобы добавить документ в список недавно открытых документов.
- PasswordDocument: string — пароль для открытия документа
- PasswordTemplate: string — пароль для открытия шаблона
- Revert : boolean — True, чтобы вернуться к сохраненному документу, если этот документ открывается повторно.
- WritePasswordDocument: string — пароль для сохранения измененного документа в файле
- WritePasswordTemplate:string — пароль для сохранения изменений в шаблоне
- Format:integer — формат открываемого документа.
Обязательным параметром метода Open является только FileName, остальные — могут отсутствовать. Если же Вам необходимо воспользоваться несколькими параметрами, то их необходимо явно указывать при вызове метода, например:
В этом случае документ открывается в режиме «Только для чтения». При таком способе вызова (с явным указанием аргументов) положение аргументов может быть произвольным.
Что касается последнего аргумента — Format, то он может принимать целочисленные значения (применительно к версиям Microsoft Word 2007 и выше) от 0 до 13. При этом, для того, чтобы открыть «родные» вордовские документы (doc) достаточно использовать значения 0 или 6.
Приведенная выше функция позволяет провести поиск и замену текстового фрагмента во всём документе. Для того, чтобы ограничить возможности пользователя при работе с шаблоном документа я обычно ставлю на необработанный файл пароль, а после обработки — пароль снимаю и сохраняю документ с другим названием в необходимую директорию.
Вот, наверное, самые-самые простые методы работы с Word в Delphi. Кстати, пишу пост и, думаю, что у кого-то из читателей может возникнуть вопрос: причём тут Delphi в Internet и Word в Delphi? :) Честно говоря, приведенный выше фрагменты кода можно использовать для нужд в Internet с натяжкой, например, при автосоставлении небольших отчётов по чему-либо. А вообще, в недалеком будущем, есть в планах поразбираться с Тезаурусом Word и попробовать составить небольшой синонимайзер для собственных нужд — он-то и пригодится нам в Internet :)
Реализация: JCL
Во-вторых, хочу заметить, что если вы используете JCL (JEDI Code Library), то весь код у вас уже есть - в файле JclFileUtils : И хотя здесь нет PathGetAbsolutePath / ExpandFileName , но эта функция тривиальна:
Реализации: вывод
Так или иначе, у вас есть богатый выбор: вы можете использовать встроенные функции, свои собственные полностью реализованные функции (взяв готовые из библиотеки JCL или написав свои) или же вы можете использовать системные функции, импортировав их из ShlwAPI.dll .
Вот как может выглядеть "функция нормализации", упомянутая выше, в разделе "Правильное решение":
А вот также упомянутая функция создания относительного пути:
Здесь ARootPath - каталог с программой, документом и т.п., относительно которого нужно создать путь. ATarget - имя файла, которое нужно сохранить в конфигурацию, документ и т.п. Result - собственно результат, который нужно сохранить. Например:
Да, вам также понадобится функция, чтобы "увести" текущий каталог на безопасное место. Вот подходящий код:
Реализация: системные функции
В-третьих, я также предлагаю вам воспользоваться функциями системы. Заметьте, что хотя эти функции относятся к функциям Оболочки (Shell), они также относятся к т.н. группе "легковесных вспомогательных функций" (Shell Lightweight Utility Functions) и импортируются из ShlwAPI.dll , а не из ShellAPI.dll . В частности, это означает, что у них нет тяжёлых зависимостей и им не нужен COM - в отличие от высококоуровневых функций Оболочки.
И для этого я предлагаю создать отдельный модуль (File / New / Other / Unit) и сохранить его, скажем, с именем ShellFileSupport.pas . В этот модуль мы поместим весь вспомогательный код. Сложные функции мы будем импортировать из системы, а простые функции напишем сами. Вот какие функции мы реализуем:
Заметьте, что некоторые функции мы реализуем сами, поэтому они работают несколько иначе, чем системные. Кроме того, для некоторых функций мы добавляем дополнительный функционал. Всё это сделано для того, чтобы упростить использование функций. Дело в том, что эти функции несколько узко-специализированы. Например, системный PathQuoteSpaces не обрабатывает кавычки внутри строки, а PathCanonicalize не преобразует некорректные разделители каталогов. Поэтому в своих функциях мы дополнительно исправляем эти упущения.
Взять готовый модуль можно здесь, а пример работы функций посмотреть здесь.
P.S. К сожалению, Delphi не поддерживает передачу кавычек в параметрах командной строки. В этом случае функции PathQuoteSpaces и PathProcessCommand используют семантику C runtime: кавычки внутри командной строки защищаются символом '\'. Но в любом случае такие параметры нельзя будет прочитать внутри Delphi-программы, если только вы не реализуете свой собственный разбор командной строки. Но зато их может прочитать другая программа, которая использует CommandLineToArgvW .
Читайте также: