Delphi занят ли файл

Обновлено: 02.07.2024

Когда вы первый раз заходите с помощью соцсетей, мы получаем публичную информацию из вашей учетной записи, предоставляемой провайдером услуги соцсети в рамках ваших настроек конфиденциальности. Мы также автоматически получаем ваш e-mail адрес для создания вашей учетной записи на нашем веб сайте. Когда она будет создана, вы будете авторизованы под этой учетной записью. Когда вы первый раз заходите с помощью соцсетей, мы получаем публичную информацию из вашей учетной записи, предоставляемой провайдером услуги соцсети в рамках ваших настроек конфиденциальности. Мы также автоматически получаем ваш e-mail адрес для создания вашей учетной записи на нашем веб сайте. Когда она будет создана, вы будете авторизованы под этой учетной записью.

sw, спасибо за отзыв :) Да в тексте опечатка. Исправлю.
ter, скоро будет и вторая часть, надо только собрать всю информацию в кучу и примерчик накрапать.

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

Полезная статейка.
С параметрами вызова Win32Check у вас беда приключилась после публикации статьи на сайте.

Логичнее использовать какую-нибудь api-шную ф-цию, типа ReadDirectoryChangesW и таймер не нужен. Самое интересное, что примеров по работе с этой api на delphi в инете полно.

CoolVlad, и где тут в потоке таймер используется?

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

Мониторинг изменений в директории с выводом информации по измененным элементам. Для этого способа используется пара функций: CreateFile и ReadDirectoryChangesW.

Мужики, выручайте. Делфа пишет что не определенно OnChange

Что я делаю не так?

Вот оно есть описано, и там же делфи материться на TForm1.OnChange

Этим разобрался. А вот 2я статья не поддается никак. Может можно pas файл выложить?

Народ , помогите:
у меня ругается на FChangeMonitor.Start; нету вообще такого свойства.
также ругается на строчку Win32Check(ChangeHandle <> INVALID_HANDLE_VALUE);
видимо при посте статьи символы неправильно отобразились.

И аналогичная проблема с событием OnChange, его тоже не видно, когда пишу procedure TForm1.

Костя, OnChange так определена? не важно в какой секции private или public, но она определена или нет?
TForm2 = class
private
procedure OnChange(Sender:TObject);
public
end;

у меня delphi7, нужно писать Resume вместо Start верно?

Олег, вполне возможно. Я этот пример гонял только на Win7 x64.

как сделать чтоб в XP работало?

Подскажите
Как можно отслеживать например 10 ну или 20 каталогов

Если не хочется использовать массив объектов TChangeMonitor, то можно воспользоваться бесплатным компонентом TJvChangeNotify из JEDI, свойство Notifications которого, позволяет создать неограниченное количество объектов мониторинга с индивидуальными событиями обработки. Допускает создание коллекции объектов наблюдения не только в runtime, но и в дизайне.

@ETCartman
Можно конечно и на форуме домохозяек задавать вопросы о Delphi/Lazarus, однако всё же разумнее это делать на специализированных форумах (если ты действительно заинтересован в том, чтобы получить качественный ответ).

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

__________________
Надеюсь, ты не социальный овощ? Это определяется делами! :welcome: ну насчет домохозяек это напрасно. хотя я конечно попробую задать на спец. форуме если не получится
вот тут пример. если не нажимать open - файл читается. если нажать - нет. даже закрыть его без ошибки нельзя.
скорее всего я где то напортачил.

Не здесь надо спрашивать. Решения легко находятся поиском по ReadDirectoryChanges - это специальная функция WinAPI. Применить её не так просто, но примеры есть. Легко найдутся.


Никакого "события" или "свойства" отркытости в Delphi/Lasarus, естественно, нет. Но есть замечательная конструкция try. except. end. Она предназначена как раз для предотвращения ошибок. Т.е. поместив действие с файлом, при котором может произойти ошибка в "ловушку", как раз и предотвращаем последствия.

Задержку надо делать в своей программе не через wait, а через Timer. В событии OnTimerTimer помещаются какие-то периодические действия. Например "стучаться" в файл. Для простеньких случаев это сойдет.

Надо учитывать, что совсем не обязательно файл, в который кто-то пишет, может быть недоступен. Это зависит от программы, которая его открыла. Например Notepad++ не блокирует открытые им файлы, в них можно писать. Но он следит, не изменился ли файл. А другие программы блокируют.

Для серьезной работы лучше пользоваться приличными библиотеками. Для Delphi просто обязательны бесплатная Jedi (JCL + JVCL). Там найдется 90% всех необходимых визуальных компонент и модулей на все случаи жизни любителя. В том числе для грамотной работы с файлами. Когда посмотришь, как люди в течение многих лет работают над казалось бы простыми действиями (например скопировать файл), понимаешь разницу между самоделкинским и профессиональным кодированием.

Для совсем серьезной работы с файловой системой лучше всего использовать библиотеки VirtualShellTools от Mustangpeak. Там есть всё - и визуальное и невизуальное. Пример NamespaceBrowser показывает, сколько интимных подробностей можно узнать про любой файл.

Здравствуйте, Аноним, Вы писали:

А>Каким образом в Делфи можно узнать какой процесс занял файл и как этот файл освободить не убивая процесс

В свое время искал, но даже узнать имя процесса занимающего файл походу нереально
Найдешь — пиши сюда.

Здравствуйте, Аноним, Вы писали:

А>>Каким образом в Делфи можно узнать какой процесс занял файл и как этот файл освободить не убивая процесс

А>В свое время искал, но даже узнать имя процесса занимающего файл походу нереально
А>Найдешь — пиши сюда.

Почему не реально?
Например Sysinternal ProcessExplorer делает это не плохо, в нём можно и хэндл от файла в процессе освободить. А вот как это делается, скорее надо в WinAPI спрашивать


Не Дельфи но общее представление можно составить.

А> и как этот файл освободить не убивая процесс
ИМХО вряд ли получится

Здравствуйте, Dimonka, Вы писали:

А>>>Каким образом в Делфи можно узнать какой процесс занял файл и как этот файл освободить не убивая процесс

А>>В свое время искал, но даже узнать имя процесса занимающего файл походу нереально
А>>Найдешь — пиши сюда.

D>Почему не реально?
D>Например Sysinternal ProcessExplorer делает это не плохо, в нём можно и хэндл от файла в процессе освободить. А вот как это делается, скорее надо в WinAPI спрашивать

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

PS по рукам надо бить за такие хаки!

Здравствуйте, Oleg A. Bachin, Вы писали:

OAB>Абстрактно послал!
OAB>насколько я помню смотри в сторону NtQuerySession, дальше перебором получаешь хендл процесса, который держит этот фай, внедряешься в процесс и рвешь хендл.

OAB>PS по рукам надо бить за такие хаки!

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

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

а где про NtQuerySession почитать можно? что это вообще такое?\
если есть ссылка, киньте

Здравствуйте, <Аноним>, Вы писали:

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

А>а где про NtQuerySession почитать можно? что это вообще такое?\
А>если есть ссылка, киньте

Текстовые файлы

Итак у всех потомков класса TStrings (TStringList, memo.Lines и т.п. ) есть методы записи и чтения в файл - SaveToFile, LoadFromFile. Преимущество - простота использования и довольно высокая скорость, недостаток - читать и писать файл можно только целиком.

1. Загрузка текста из файла в Memo:

2. Сохранение в файл:

3. А вот так можно прочитать весь файл в строку:

Паскалевский метод доступа

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

Итак, для доступа к текстовым файлам используется переменная типа TextFile. До сих пор не совсем понимаю что это такое физически - что-то типа "внутреннего" паскалевского Handle на файл.

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

1) Определяем файловую переменную:

2) Ассоциируем ее:

3) Теперь надо этот файл открыть, есть 3 варианта:

  1. файла нет или он должен быть перезаписан, открытие для записи: Rewrite(f)
  2. файл есть и его надо открыть для чтения (с первой строки): Reset(f)
  3. файл есть и его надо открыть для дописования строк в конец: Append(f)

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

  • Перезаписать весть файл
  • Читать с первой строки
  • Дописать что-то в конец
  • Читать и писать файл целиком (см. выше работу через TStrings)

В конце работы открытый файл нужно закрыть:

Теперь пусть у нас есть строковая переменная s для чтения строки из файла

Чтение предварительно открытого файла:

ReadLn(f, s) - будет прочитанна текущая строка и позиция чтения переведена на следующую позицию.

А как прочитать весь файл?

Хорошо, а если файл несколько метров есть ли способ поставить какой-нибудь ProgressBar или Gauge чтобы показывал сколько считанно? Есть, но не совсем прямой - не забыли, сколько строк в файле заранее мы не знаем, узнать можно только прочитав его весь, но показометер мы все-таки сделаем:

Теперь комментарии к коду.

  1. Функию GetFileSize я рсссмотрю после, она немного по другому подходит к чтению файла (кстати я знаю еще по крайней мере 3 способа ее реализации, поэтому не нужно указывать что это можно сделать легче, быстрее или просто по другому - просто давайте разберем это позже)
  2. Переменная i - все время указывает на количество байт которое мы считали - мы определяем длину каждой строки и прибавляем 2 (символы конца строки). Зная длину файла в байтах и сколько байт прочитано можно оценить и прогресс, но
  3. Если ставить изменение прогресса после каждой строки, то это очень сильно тормознет процесс. Поэтому вводим переменную j и обновляем прогресс например 1 раз на 1000 прочитанных строк
  4. Переменная Canceled - глобальная переменная. Поставьте на форму кнопку, в обработчике нажатия поставьте Canceled:=True; и нажатие кнопки прервет чтение файла.

Теперь как писать в текстовый файл:

Запись целой строки:

Запись кусочка строки(те следующая операция записи будет произведена в ту же строку):

Если переменная s содержит больше 255 символов (т.е. является длинной строкой), то таким способом ни фига не запишится, в файл вместо строки попадут 4 байта указателя на нее. Надо делать так:

Работа через WinAPI

Раздел написан Podval (примеры к сожалению на С++)

Любителям WinAPI посвящается. Функции FileOpen, FileSeek, FileRead. Возьмем форму, положим на нее кнопку, грид и Опен диалог бокс. Это для Билдера, но какая нам в данном случае разница?

Потренируемся еще. Функции FileExists, RenameFile, FileCreate, FileWrite, FileClose. Бросим на форму Save dialog box.

(с) Оба примера взяты из хелпа по Borland C++ Builder 5.

Первоисточник тот же.

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

В этом примере идет поиск в текущем каталоге и каталоге Windows

В дополнение к Дате/Времени

Для конвертации возвращаемого значения в TDateTime:

Типизированные файлы

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

Объявляем файл байтов:

Ассоциируем файловую переменную с физическим файлом:

Теперь мы можем либо перезаписать/создать файл:

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

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

Теперь функции работы с файлом:

Все эти функции не работают с файлами большими 2 Gb.

После работы файл надо закрыть:

Приведенные выше механизмы будут работать с любым файлом, так как любой файл можно считать файлом байтов. Теперь где это можно использовать? В принципе везде, но в подавляющем большинстве случаев это будет очень неудобно, ведь скорость считывания при чтении по байтам будет на порядки более низкой чем другими способами. Однако в некоторых случаях этот способ может быть очень полезен. Например в программе вам надо заменить 100й байт файла на другой, или прочитать 100й байт файла, например во всяких читерских программах, при взломе и т.п. Здесь такой доступ будет весьма удобен. Гораздо более интересным представляется дальнейшее развитие технологии типизированных файлов (их еще лет 15 назад называли "Файлы прямого доступа"). Представим себе, что файл состоит не из байт а из более сложных структур. Например мы имеем некоторую информацию в виде:

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

и файл этого типа:

Теперь мы можем читать и писать сразу целую структуру, абсолютно так же как и если бы это был один байт:

Все остальные функции приведенные в предыдущей статье будут работать так же, только одно отличие - Seek и Size оперируют не с количеством байт, а с количеством записей.

Нетипизированные файлы

Идем дальше. Есть такое понятие как нетипизированный файл. Это такой файл который содержит разнородные элементы. Например файл EXE - вначале он имеет заголовок, затем двоичный код, в конце какие-то ресурсы. Все части файла имеют разную длину и разную структуру. Тут уже обратится к произвольному элементу сложно, обычно надо вначале узнать где этот элемент находится, подчас это записано в предыдущем куске информации. Работа с такими файлами достаточно сложна и требует вручную разработки алгоритмов его чтения, но в связи гибкостью структуры и компактностью такие файлы составляют большинство. Для работы с нетипизированными файлами используют процедуры BlockRead и BlockWrite, которые позволяют читать/писать произвольное количество байт. Привожу пример пользования этими функциями из справки по Дельфи:

Этот код копирует из одного файла в другой. Замечания по поводу этого метода работы с файлами - плюсы - очень высокая скорость, особенно если размер буффера увеличить до 64kb-512kb, что позволит считывать файл достаточно большими кусками, чтобы обеспечить отсутствие простоев винчестера, к тому же обеспечивается очень высокая гибкость в работе. Минусы - сложность разработки, необходимость вручную писать все детали механизма чтения/записи и интерпретации данных.

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

Файловые потоки

Теперь разберем возможности работы потомка TStream - TFileStream - файловый поток. Этот класс был специально введен для работы с файлами. Для работы с файловым потоком Вам надо записать в Uses модули classes, Sysutils (classes - включает в себя собственно определение класса, Sysutils - некоторые константы необходимые для работы).

Вот пример записи/перезаписи файла:

Теперь небольшой разбор:

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

Теперь метод Write - этим методом в файл пишется любая информация из буфера любого типа, Вам надо указать только буффер и количество записываемых байтов. В данном случае используется переменная типа String в качестве буффера, но так как для длинных строк она представляет собой лишь указатель, то конструкция "pointer(s)^" заставляет обращаться именно к ее содержимому.

А вот этот код демонстрирует чтение файла с использованием файлового потока:

И пояснения к коду:

  1. Никаких проверок длину файла и его наличие здесь не делается - это демонстрационный код, а не готовая процедура чтения.
  2. Файл мы считываем в буффер типа PChar (с тем же успехом можно использовать массив или любой другой контейнер). Для тех кто не помнит - процедуры GetMem(p, 255) и FreeMem(p) - распределение памяти для строки и освобождение памяти.
  3. Метод потока Seek позволяет установить текущую позицию считывания/записи файла. Первый параметер - номер байта, второй - это от чего считать этот байт (у нас считать от начала файла), возможны варианты:
    • soFromBeginning - от начала файла
    • soFromCurrent - от текущей позиции считывания
    • soFromEnd - от конца файла (в этом случае номер байта должен быть отрицательным или равным нулю)
  4. Собственно считывание из потока осуществляется методом read, в котором указывается в качестве параметров буфер в который мы читаем и желаемое количество байт для чтения. Метод read является функцией, которая возвращает количество байт реально прочитанных из потока.

Заканчивая о файловых потоках хочу упомянуть о методе

CopyFrom который позволяет перекачивать информацию из одного потока в другой и о свойствах:

Size - размер файла
Position - текущая позиция чтения/записи потока

Работа с файловыми потоками весьма быстра, этот класс, являсь классом VCL, в то же время базируется на низкоуровневых функциях Windows, что обеспечивает очень высокую скорость работы и стабильность операций. К тому же многие компоненты и классы VCL поддерживаю прямое чтение и запись с файловыми потоками, что занчительно упрощает работу - например TStringList, TBlobField, TMemoField и другие.

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

Работа через Handle

Еще один способ работы с файлами - это открытие Handle на файл и работу через него. Тут есть 2 варианта - можно использовать функции Дельфи или использовать WinAPI напрямую.

При использовании функций Дельфи можно применять следующие функции:

FileOpen(FileName, fmOpenWrite or fmShareDenyNone) - функция открывает файл и возвращает целое цисло - Handle на файл. Параметры функции - имя файла и тип доступа (все типы доступа я перечислил ранее). Если файл успешно открыт то Handle должен быть положительным цислом, отрицательное число - это код ошибки.

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

FileClose(Handle: Integer) - закрывает файл

FileRead(Handle: Integer; var Buffer; Count: Integer): Integer;
FileWrite(Handle: Integer; const Buffer; Count: Integer): Integer;

Эти функции для чтения/записи файла, где Buffer любая переменная достаточного размера для чтения/записи куска информации (обычно типа PChar или массив), Count-количество байт, которое Вы желаете записать/прочитать. Функции возвращают количество байт которые реально были прочитанны или записаны.

Этот тип доступа к файлам применяется весьма редко. Дело в том что он практически дублирует соответствующие функции WinAPI и к тому же обычно работает несколько медленнее, чем например потоки. И все же использование функций FileOpen и FileClose не лишено привлекательности. Наряду с тем что эти функции намного легче в использовании соответствующих функций WinAPI (можете сравнить - FileOpen имеет 2 параметра, cooтветствующая функция WinAPI - CreateFile имеет 7 параметров, большая часть из которых реально требуется лишь в ограниченном числе случаев) этот путь доступа открывает возможность прямого использования всех функций WinAPI про работе с файлами, которые требуют Handle на открытый файл.

Файловые операции

Дельфи предоставляет довольно широкие возможности по файловым операциям без использования механизмов открытия/закрытия файлов.

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

ChDir(NewCurrentPath: string); - изменяет текущий каталог (в среде Windows сие конечно не так актуально как в ДОС, но все же), прочитать же текущий каталог можно функцией GetCurrentDir, а текущий каталог для определенного драйва - GetDir.

CreateDir(const Dir: string): Boolean; - создает каталог. При этом предыдущий уровень должен присутствовать. Если вы хотите сразу создать всю вложенность каталогов используйте функцию ForceDirectories(Dir: string): Boolean; Обе функции возвращают True если каталог создан

DiskFree(Drive: Byte): Int64; - дает свободное место на диске. Параметер - номер диска 0 = текущий, 1 = A, 2 = B, и так далее

DiskSize(Drive: Byte): Int64; - размер винта. Обратите внимание на то что для результата этой и предыдущей функций абсолютно необходимо использовать переменную типа Int64, иначе макимум того что вы сможете прочитать правильно будет ограничен 2Gb

FileExists(const FileName: string) - применяется для проверки наличия файла

FileGetAttr(const FileName: string): Integer;
FileSetAttr(const FileName: string; Attr: Integer): Integer; - функции для работы с атрибутами файлов. Вот список возможных атрибутов:

RemoveDir(const Dir: string): Boolean; - удаляет папку(пустую)
DeleteFile(const FileName: string): Boolean; - удаляет файл
RenameFile(const OldName, NewName: string) - переименовывает файл

Информация о файле

Привожу пример функции которая собирает довольно большое количество информации о выбранном файле:

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

Поиск файлов

Теперь поговорим о поиске файлов. Для этой цели могут использоваться процедуры FindFirst, FindNext, FindClose, при участии переменной типа TSearchRec которая хранит информацию о текущем статусе поиска и характеристики последнего найденного файла.

Пример иллюстрирующий поиск всех файлов и каталогов в определенном каталоге:

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