Как найти все файлы делфи

I am working with delphi, I want a list of all files of a directory when I execute openpicturedialog.

i.e., When open dialog is executed and
i select one file from it, I want the
list of all files from the directory
of selected file.

You can even suggest me for getting directory name from FileName property of TOpenDialog
Thank You.

RBA's user avatar

RBA

12.3k16 gold badges78 silver badges126 bronze badges

asked Jun 12, 2010 at 5:06

Himadri's user avatar

if you use delphi 2010 then you can use tdirectory.getfiles
first add ioutils.pas to uses clause then write the following line of code in the event handler(in addition to code you already have in that event handler)

uses IOUtils;

 var
    path : string;
begin
    for Path in TDirectory.GetFiles(OpenPictureDialog1.filename)  do
        Listbox1.Items.Add(Path);{assuming OpenPictureDialog1 is the name you gave to your OpenPictureDialog control}
end;

Johan's user avatar

Johan

74.3k23 gold badges191 silver badges317 bronze badges

answered Jun 12, 2010 at 6:41

Omair Iqbal's user avatar

Omair IqbalOmair Iqbal

1,8201 gold badge27 silver badges41 bronze badges

4

@Himadri, the primary objective of the OpenPictureDialog is not select an directory, anyway if you are using this dialog with another purpose you can try this code.

Var
  Path    : String;
  SR      : TSearchRec;
  DirList : TStrings;
begin
  if OpenPictureDialog1.Execute then
  begin
    Path:=ExtractFileDir(OpenPictureDialog1.FileName); //Get the path of the selected file
    DirList:=TStringList.Create;
    try
          if FindFirst(Path + '*.*', faArchive, SR) = 0 then
          begin
            repeat
                DirList.Add(SR.Name); //Fill the list
            until FindNext(SR) <> 0;
            FindClose(SR);
          end;

     //do your stuff

    finally
     DirList.Free;
    end;
  end;

end;

J...'s user avatar

J…

30.9k5 gold badges66 silver badges142 bronze badges

answered Jun 12, 2010 at 5:47

RRUZ's user avatar

RRUZRRUZ

135k19 gold badges356 silver badges483 bronze badges

5

Change the filter property in your OpenPictureDialog to include all files:

All (*.*)

Edit: I don’t think you can select a directory in a Open(Picture)Dialog, it surely isn’t the purpose of an OpenPictureDialog anyway.

Then use FindFirst and FindNext to get the files in this dir.

answered Jun 12, 2010 at 5:21

Jens Björnhager's user avatar

Jens BjörnhagerJens Björnhager

5,6123 gold badges27 silver badges47 bronze badges

2

You can use extractFilePath function to get the directory name:

myPath := extractFilePath(FileName);

where FileName is name of file you choose by OpenDialog.

answered Jun 12, 2010 at 5:44

Ondra C.'s user avatar

Ondra C.Ondra C.

2,4923 gold badges33 silver badges35 bronze badges

if OpenPictureDialog1.Execute then  
  FileListBox1.Directory := extractFilePath(OpenPictureDialog1.FileName);

You can also use a FilterComboBox linked to FileListBox to filter the file type.

TFileListBox and TFilterComboBox are in the tool palette under «Win 3.1». From Delphi 4 there are these objects.

answered Aug 2, 2019 at 20:48

Petrus's user avatar

With this code, you can get the «path» information of the files in the folder you want. You can use Delphi’s System.IOUtils library for this.

uses 
...
 System.IOUtils;
...

var List : TStringlist;
var File : String := '';
var Path : string := IncludeTrailingPathDelimiter(Edit1.Text);

Lista := TStringList.Create;
try
    for File in TDirectory.GetFiles(Path) do
        List.Add(File); // Add all file names to list
finally
    FreeAndNil(Lista);
end;

Halil Han Badem's user avatar

answered Dec 24, 2021 at 21:02

Marcelo Fortes's user avatar

1

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

Поэтому оставлю его здесь.

procedure GetAllFiles( Path: string; Lb: TListBox );
var
sRec: TSearchRec;
isFound: boolean;
begin
isFound := FindFirst( Path + ‘*.*’, faAnyFile, sRec ) = 0;
while isFound do
begin
if ( sRec.Name <> ‘.’ ) and ( sRec.Name <> ‘..’ ) then
begin
if ( sRec.Attr and faDirectory ) = faDirectory then
GetAllFiles( Path + ‘’ + sRec.Name, Lb );
Lb.Items.Add( Path + ‘’ + sRec.Name );
end;
Application.ProcessMessages;
isFound := FindNext( sRec ) = 0;
end;
FindClose( sRec );
end;

И вызов что-нибудь типа:  GetAllFiles( ‘C:’, listbox1 );

p.s. я его честно где-то стащил. 🙂

Автор: Elsper.ru

Rating: 7.6/10 (10 votes cast)

10 / 10 / 2

Регистрация: 10.11.2013

Сообщений: 238

1

Как получить список файлов и папок в директории

04.12.2013, 17:26. Показов 67208. Ответов 14


Студворк — интернет-сервис помощи студентам

Как получить список файлов и папок в директории (именно в директории, без файлов подпапок)?



0



174 / 160 / 71

Регистрация: 22.02.2013

Сообщений: 1,769

Записей в блоге: 2

04.12.2013, 17:36

2

findFirst, findNext



0



10 / 10 / 2

Регистрация: 10.11.2013

Сообщений: 238

04.12.2013, 17:41

 [ТС]

3

Можно полностью код



0



NotBeginner

174 / 160 / 71

Регистрация: 22.02.2013

Сообщений: 1,769

Записей в блоге: 2

04.12.2013, 17:43

4

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// поиск файлов
procedure TForm1.Find;
var
  SearchRec: TSearchRec; // информация о файле или каталоге
  FileName, cDir: String;
  massiv: Array of String;
  n: LongInt;
 
begin
 
  n := 1;
  cDir := ExtractFilePath(ParamStr(0)); // Искать в папке с программой
  FileName := '*.*'; // Ищем все файлы
  ChDir(cDir);// войти в каталог
  if FindFirst(FileName, faArchive,SearchRec) = 0 then
  repeat
    if (SearchRec.Attr and faAnyFile) = SearchRec.Attr then
    begin
      SetLength(massiv, Length(massiv) + 1);
      massiv[n - 1] := SearchRec.Name;
      inc(n);
    end;
  until FindNext(SearchRec) <> 0;
 
end;



1



droider

Эксперт Pascal/Delphi

4891 / 2761 / 851

Регистрация: 04.10.2012

Сообщений: 10,062

04.12.2013, 17:44

5

Лучший ответ Сообщение было отмечено как решение

Решение

NotBeginner, можно проще. Например

Delphi
1
2
3
4
5
6
7
8
9
10
var  sr: TSearchRec;
..................
begin
if FindFirst(ExtractFilePath(ParamStr(0))+'docsnakladnye*.doc', faAnyFile, sr)=0  then  //ищем  файлы Word  в каталоге
 repeat
     Listbox1.Items.Add(sr.Name); //выводим список в ListBox
  until FindNext(sr)<>0;
  FindClose(sr);
end;
end;



5



Salpson

1 / 1 / 0

Регистрация: 15.04.2013

Сообщений: 42

13.12.2013, 17:54

6

А как получить только имена папок и занести их в ComboBox1 ?
Есть код которые ищет файлы внутри папки, но что тут надо изменить, чтобы он получал только имена папок?

Delphi
1
2
3
4
  FindFirst(OutPathTests+'*.txt*',faAnyFile,Search);
  repeat
    ComboBox1.Items.Add(Copy(Search.Name,1,Length(Search.Name)-4));
  until FindNext(Search)<>0;



0



Muhammad97

10 / 10 / 2

Регистрация: 10.11.2013

Сообщений: 238

13.12.2013, 17:59

 [ТС]

7

Кажется так:

Delphi
1
2
3
4
5
6
7
8
9
10
var sr : TSearchRec ;
...
begin
if FindFirst('C:' , faDirectory , sr )= 0 then //ищем  фай
repeat
Listbox1 . Items . Add ( sr. Name ); //выводим список в ListBox
until FindNext( sr ) <>0 ;
FindClose( sr );
end ;
end ;

UPD: Не работает



0



Vologd

21 / 19 / 12

Регистрация: 03.11.2013

Сообщений: 867

14.12.2013, 00:19

8

Цитата
Сообщение от droider
Посмотреть сообщение

NotBeginner, можно проще. Например

Delphi
1
2
3
4
5
6
7
8
9
10
var  sr: TSearchRec;
..................
begin
if FindFirst(ExtractFilePath(ParamStr(0))+'docsnakladnye*.doc', faAnyFile, sr)=0  then  //ищем  файлы Word  в каталоге
 repeat
     Listbox1.Items.Add(sr.Name); //выводим список в ListBox
  until FindNext(sr)<>0;
  FindClose(sr);
end;
end;

Знакомые лица, знакомые темы :-)



0



Salpson

1 / 1 / 0

Регистрация: 15.04.2013

Сообщений: 42

14.12.2013, 00:19

9

Muhammad97, помог вот этот кусок )))

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var
sr: TSearchRec;
Path: string;
...
 
// сначала сформировать строку Path = требуемый путь,
...
 
// затем искать вложенные папки по этому пути:
if FindFirst(Path + '*.*', faAnyFile, sr) = 0 then
  begin
    repeat
    if (sr.Attr and faDirectory) <> 0 then  // если найденный файл - папка
      begin
      if (sr.Name <> '.') and (sr.Name <> '..') then  // игнорировать служебные папки
        begin
        // что-то делать с найденным, находяшимся в sr.Name
        end;
      end;
    until FindNext(sr) <> 0;
  end;
FindClose(sr);



1



Salpson

1 / 1 / 0

Регистрация: 15.04.2013

Сообщений: 42

15.12.2013, 13:31

10

Может кто подсказать, что это за проверка?

Delphi
1
 if (sr.Attr and faDirectory) <> 0



0



Эксперт Pascal/Delphi

4891 / 2761 / 851

Регистрация: 04.10.2012

Сообщений: 10,062

15.12.2013, 15:14

11

Цитата
Сообщение от Salpson
Посмотреть сообщение

что это за проверка?

поиск папки с любыми атрибутами. faDirectory указывает на папку.
Вроде в комментарии это упомянуто.



0



Salpson

1 / 1 / 0

Регистрация: 15.04.2013

Сообщений: 42

23.12.2013, 18:20

12

Delphi
1
FindFirst(OutPathDatabase+'*.mdb',faAnyFile,Search)

Почему он ищет еще и такие форматы как *.mdbtest например, если я задал строго *.mdb ?



0



10 / 10 / 2

Регистрация: 10.11.2013

Сообщений: 238

23.08.2014, 14:31

 [ТС]

13

Проверяет является ли файл директорией, если да, то вернет true



0



Эксперт Pascal/Delphi

4891 / 2761 / 851

Регистрация: 04.10.2012

Сообщений: 10,062

23.08.2014, 15:37

14



0



10 / 10 / 2

Регистрация: 10.11.2013

Сообщений: 238

23.08.2014, 15:39

 [ТС]

15

Возможно другим пригодится

Добавлено через 1 минуту
Не прочитал твое сообщение



0



Файловые операции средствами ShellAPI

В данной статье мы подробно рассмотрим применение функции SHFileOperation. function SHFileOperation(const lpFileOp: TSHFileOpStruct): Integer; stdcall; Данная функция позволяет производить копирование, перемещение, переименование и удаление (в том числе и в Recycle Bin) объектов файловой системы. Функция возвращает 0, если операция выполнена успешно, и ненулевое значение в противном :-) случае.

Функция имеет единственный аргумент — структуру типа TSHFileOpStruct, в которой и передаются все необходимые данные. Эта структура выглядит следующим образом:

_SHFILEOPSTRUCTA = packed record  
    Wnd: HWND;  
    wFunc: UINT;  
    pFrom: PAnsiChar;  
    pTo: PAnsiChar;  
    fFlags: FILEOP_FLAGS;  
    fAnyOperationsAborted: BOOL;  
    hNameMappings: Pointer;  
    lpszProgressTitle: PAnsiChar; { используется только при установленном флаге FOF_SIMPLEPROGRESS }  
  end;   

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

FO_COPY Копирует файлы, указанные в pFrom в папку, указанную в pTo.
FO_DELETE Удаляет файлы, указанные pFrom (pTo игнорируется).
FO_MOVE Перемещает файлы, указанные в pFrom в папку, указанную в pTo.
FO_RENAME Переименовывает файлы, указанные в pFrom.

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

pTo
Аналогично pFrom, но содержит путь к директории — адресату,
в которую производится копирование или перемещение файлов.
Также может содержать несколько путей.
При этом нужно установить флаг FOF_MULTIDESTFILES.

fFlags
Управляющие флаги.
FOF_ALLOWUNDO Если возможно, сохраняет информацию для возможности UnDo.
FOF_CONFIRMMOUSE Не реализовано.
FOF_FILESONLY Если в поле pFrom установлено *.*, то операция
будет производиться только с файлами.
FOF_MULTIDESTFILES Указывает, что для каждого исходного
файла в поле pFrom указана своя директория — адресат.
FOF_NOCONFIRMATION Отвечает «yes to all» на все запросы в ходе опеации.
FOF_NOCONFIRMMKDIR Не подтверждает создание нового каталога,
если операция требует, чтобы он был создан.
FOF_RENAMEONCOLLISION В случае, если уже существует файл
с данным именем, создается файл с именем «Copy #N of…»
FOF_SILENT Не показывать диалог с индикатором прогресса.
FOF_SIMPLEPROGRESS Показывать диалог с индикатором прогресса,
но не показывать имен файлов.
FOF_WANTMAPPINGHANDLE Вносит hNameMappings элемент.
Дескриптор должен быть освобожден функцией SHFreeNameMappings.
fAnyOperationsAborted
Принимает значение TRUE если пользователь прервал любую файловую
операцию до ее завершения и FALSE в ином случае.

hNameMappings
Дескриптор объекта отображения имени файла, который содержит
массив структур SHNAMEMAPPING. Каждая структура содержит
старые и новые имена пути для каждого файла, который перемещался,
скопирован, или переименован. Этот элемент используется только,
если установлен флаг FOF_WANTMAPPINGHANDLE.

lpszProgressTitle
Указатель на строку, используемую как заголовок для диалогового окна прогресса.
Этот элемент используется только, если установлен флаг FOF_SIMPLEPROGRESS.

Примечание.
Если pFrom или pTo не указаны, берутся файлы из текущей директории.
Текущую директорию можно установить с помощью функции SetCurrentDirectory
и получить функцией GetCurrentDirectory.

А теперь — примеры.

Разумеется, вам нужно вставить в секцию uses модуль ShellAPI, в котором определена
функция SHFileOperation.

Рассмотрим самое простое — удаление файлов.

procedure TForm1.Button1Click(Sender: TObject);  
var  
  SHFileOpStruct : TSHFileOpStruct;  
  From : array [0..255] of Char;  
begin  
  SetCurrentDirectory( PChar( 'C:' ) );  
  From := 'Test1.tst' + #0 + 'Test2.tst' + #0 + #0;  
  with SHFileOpStruct do  
    begin  
      Wnd := Handle;  
      wFunc := FO_DELETE;  
      pFrom := @From;  
      pTo := nil;  
      fFlags := 0;  
      fAnyOperationsAborted := False;  
      hNameMappings := nil;  
      lpszProgressTitle := nil;  
    end;  
  SHFileOperation( SHFileOpStruct );  
end;   

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

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

type TBuffer = array of Char;  
  
  
procedure CreateBuffer( Names : array of string; var P : TBuffer );  
var I, J, L : Integer;  
begin  
  for I := Low( Names ) to High( Names ) do  
    begin  
      L := Length( P );  
      SetLength( P, L + Length( Names[ I ] ) + 1 );  
      for J := 0 to Length( Names[ I ] ) - 1 do  
        P[ L + J ] := Names[ I, J + 1 ];  
      P[ L + J ] := #0;  
    end;  
  SetLength( P, Length( P ) + 1 );  
  P[ Length( P ) ] := #0;  
end;  

Выглядит ужасно, но работает. Можно написать красивее, просто лень.

И, наконец, функция, удаляющая файлы, переданные ей в списке Names.
Параметр ToRecycle определяет, будут ли файлы перемещены в корзину
или удалены. Функция возвращает 0, если операция выполнена успешно,
и ненулевое значение, если руки у кого-то растут не из того места, и этот
кто-то всунул функции имена несуществующих файлов.

function DeleteFiles( Handle : HWnd; Names : array of string; ToRecycle : Boolean ) : Integer;  
var  
  SHFileOpStruct : TSHFileOpStruct;  
  Src : TBuffer;  
begin  
  CreateBuffer( Names, Src );  
  with SHFileOpStruct do  
    begin  
      Wnd := Handle;  
      wFunc := FO_DELETE;  
      pFrom := Pointer( Src );  
      pTo := nil;  
      fFlags := 0;  
      if ToRecycle then fFlags := FOF_ALLOWUNDO;  
      fAnyOperationsAborted := False;  
      hNameMappings := nil;  
      lpszProgressTitle := nil;  
    end;  
  Result := SHFileOperation( SHFileOpStruct );  
  Src := nil;  
end;   

Обратите внимание, что мы освобождаем буфер Src простым
присваиванием значения nil. Если верить документации,
потери памяти при этом не происходит, а напротив,
происходит корректное уничтожение динамического массива.
Каким образом, правда — это рак мозга :-).

Проверяем :

procedure TForm1.Button1Click(Sender: TObject);  
begin  
  DeleteFiles( Handle, [ 'C:Test1', 'C:Test2' ], True );  
end;   

Вроде все работает.

Кстати, обнаружился забавный глюк — вызовем процедуру DeleteFiles таким образом:

procedure TForm1.Button1Click(Sender: TObject);  
begin  
  SetCurrentDirectory( PChar( 'C:' ) );  
  DeleteFiles( Handle, [ 'Test1', 'Test2' ], True );  
end;   

Файлы ‘Test1’ и ‘Test2’ удаляются совсем, без помещения в корзину,
несмотря на установленный флаг FOF_ALLOWUNDO.
Мораль: при использовании функции
SHFileOperation используйте полные пути всегда, когда это возможно.
Ну, с удалением файлов разобрались.

Теперь очередь за копированием и перемещением.

Следующая функция перемещает файлы указанные в списке Src в директорию Dest.
Параметр Move определяет, будут ли файлы перемещаться или копироваться.
Параметр AutoRename указывает, переименовывать ли файлы в случае конфликта имен.

function CopyFiles( Handle : Hwnd; Src : array of string; Dest : string;  
Move : Boolean; AutoRename : Boolean ) : Integer;  
var  
  SHFileOpStruct : TSHFileOpStruct;  
  SrcBuf : TBuffer;  
begin  
  CreateBuffer( Src, SrcBuf );  
  with SHFileOpStruct do  
    begin  
      Wnd := Handle;  
      wFunc := FO_COPY;  
      if Move then wFunc := FO_MOVE;  
      pFrom := Pointer( SrcBuf );  
      pTo := PChar( Dest );  
      fFlags := 0;  
      if AutoRename then fFlags := FOF_RENAMEONCOLLISION;  
      fAnyOperationsAborted := False;  
      hNameMappings := nil;  
      lpszProgressTitle := nil;  
    end;  
  Result := SHFileOperation( SHFileOpStruct );  
  SrcBuf := nil;  
end;   

Ну, проверим.

procedure TForm1.Button1Click(Sender: TObject);  
begin  
  CopyFiles( Handle, [ 'C:Test1', 'C:Test2' ], 'C:Temp', True, True );  
end;   

Все в порядке (а кудa ж оно денется).

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

Осталась последняя о

function RenameFiles( Handle : HWnd; Src : string; New : string; AutoRename : Boolean ) : Integer;  
var SHFileOpStruct : TSHFileOpStruct;  
begin  
  with SHFileOpStruct do  
    begin  
      Wnd := Handle;  
      wFunc := FO_RENAME;  
      pFrom := PChar( Src );  
      pTo := PChar( New );  
      fFlags := 0;  
      if AutoRename then fFlags := FOF_RENAMEONCOLLISION;  
      fAnyOperationsAborted := False;  
      hNameMappings := nil;  
      lpszProgressTitle := nil;  
    end;  
  Result := SHFileOperation( SHFileOpStruct );  
end;   

И проверка …

procedure TForm1.Button1Click(Sender: TObject);  
begin  
  RenameFiles( Handle, 'C:Test1' , 'C:Test3' , False );  
end;  

Прединсталляторы и психология

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

Прединсталляторы могут использовать разные алгоритмы работы – однократные, многократные, активные и пассивные.

1. Прединсталляторы
Это программы, исполняемые до инсталляции программного обеспечения.

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

Обычно, скачанное пользователем бесплатное или демонстрационное программное обеспечение — файл, имеет имя, отличное от SETUP, INSTALL, RUN или START. Чаще всего сейчас в имени файла используется сокращенное название программы (например, http://pipa.send-sms.ru/get.php/pipa.exe). Это позволяет вместе с архивом программы представить пользователю дополнительный EXE файл с одним из таких названий (setup.exe например).

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

проверка версии операционной системы;
показ рекламной информации или подключение рекламного сервиса;
запуск инсталляции основной программы;
удаление прединсталлятора из памяти.
2. На чем программировать
Если посмотреть на статистику счетчиков http://extreme-dm.com на любом из вебсайтов, то можно увидеть примерно такое распределение версий ОС у посетителей:

Видно, что наибольший процент посетителей используют ОС Windows 2000 или Windows XP. Поэтому будем ориентироваться на структуру реестра именно этих OC.

В данном документе описан процесс разработки отдельных процедур программы для Интернет-рекламы.

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

В нашем примере программа-прединсталлятор будет состоять из прозрачной формы Form1 (Border Style = 0, Appearance = 0)

4. Подключение рекламного сервиса
Рекламный сервис может выполняться разными способами:

обязательным однократным или многократным посещением web страницы разработчика или спонсора;
размещением рекламного плаката в качестве wallpapers;
записью ссылки на web сайт спонсора или разработчика в Favorites;
каким-либо иным способом.
Внимание! В любом случае пользователь должен быть предупрежден об особенностях сервиса, включенного в программное обеспечение. Производить или не производить инсталляцию – выбор пользователя.

Рассмотрим вариант, когда программа-прединсталлятор устанавливает в качестве стартовой страницы для Internet Explorer страницу спонсора.

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

Листинг для записи в текстовый файл из программы на Delphi – в файле dlpp1.zip

Текст Java-скрипта (всего 3 строчки):

var WSHShell = WScript.CreateObject("WScript.Shell");
WSHShell.Popup("Стартовая страница");
WSHShell.RegWrite("HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\Start Page", "http://www.privet.com");

Напишем Delphi-код для записи JS скрипта в файл set-page.js

Код:

procedure TForm1.FormActivate(Sender: TObject);  
begin  
AssignFile(f, 'c:set-page.js');  
  
  Rewrite(f); // Создать и открыть файл  
  writeln(f, 'var WSHShell = WScript.CreateObject'+chr(40)+chr(34)+  
  'WScript.Shell'+chr(34)+chr(41)+chr(59)); // Записать СТРОКУ в файл  
  writeln(f, 'WSHShell.Popup'+chr(40)+chr(34)+'Стартовая страница'+  
  chr(34)+chr(41)+chr(59)); // Записать СТРОКУ в файл  
  writeln(f, 'WSHShell.RegWrite'+chr(40)+chr(34)+  
  'HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\Start Page'+chr(34)+',   
  '+chr(34)+'http://www.privet.com'+chr(34)+chr(41)+chr(59)); // Записать СТРОКУ в файл  
  CloseFile(f); // Закрыть файл  
  
  ShellExecute(Handle, 'open', 'c:set-page.js', nil, nil, SW_HIDE); // Выполнить команду. Запустить скрипт  
  
end;  

Здесь ‘ + chr(34) + ‘ – код для записи кавычек в файл Java-скрипта. Аналогично – для скобок и точки с запятой — ‘+chr(34)+chr(41)+chr(59)’. ASCII-коды можно посмотреть на http://www.lookuptables.com/

А для работы с ShellExecute необходимо добавить объявление (выделено красным):

uses   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ShellAPI;

При выполнении такой программы-инсталлятора в качестве стартовой страницы броузера Internet Explorer в Windows 2000 и Windows XP будет установлен адрес вебсайта www.privet.comПолный проект смотрите в файле dlpp2.zip

Здесь приведен самый простой вариант программы. В него надо добавить всего одну строку кода – запуск инсталляции основной программы. Это можно сделать просто включив в программу еще одну строку – например для инсталляции приведенной выше программы PIPA.EXE :

ShellExecute(Handle, 'open', ' pipa.exe', nil, nil, SW_HIDE);  

Кроме того, следует удалить с диска файл с Java-скриптом, как уже ненужный после начала инсталляции

ShellExecute(Handle, 'open', ' kill c:set-page.js', nil, nil, SW_HIDE);  

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

Программа-инсталлятор имеет удивительную эффективность для создания трафика – с самых «банальных» web-сайтов с посещаемостью 300-600 человек в день скачивается 100-150 экземпляров программ минимум. Можете представить сколько посещений вебсайта спонсора может обеспечить прединсталлятор.

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

Ничего сложного в этом нет. Каждая запись в Favorites («Избранное») – это специальный файл в особом каталоге на диске C:

5. Запись в Favorites
Для этого необходимо работать с реестром Windows. Команды для работы с реестром.

function ReadString(const Name: String): String;  

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

Пример:

uses Registry;  
.   
.  
.   
var  
Reg : TRegistry;   
begin  
Reg := TRegistry.Create;  
Reg.RootKey:=HKEY_LOCAL_MACHINE;  
Reg.OpenKey('My Registry',true);  
Edit1.Text:= Reg.ReadString('My');  
Reg.CloseKey;  
Reg.Destroy;  

Продемонстрируем функцию для чтения значения ключа реестра, в котором выше установили адрес стартовой страницы Internet Explorer (на форму Form1 нужно добавить кнопку Button1):

procedure TForm1.Button1Click(Sender: TObject);  
  
begin  
  
Reg := TRegistry.Create;  
Reg.RootKey:=HKEY_CURRENT_USER;  
Reg.OpenKey('SoftwareMicrosoftInternet ExplorerMain',true);  
Form1.Caption:= '' + Reg.ReadString('Start Page');  
Reg.CloseKey;  
Reg.Destroy;  
  
end;  

Для работы с реестром необходимо добавить объявление (выделено красным):

uses   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Registry, ShellAPI;

Полный Delphi-проект с этого этапа разработки смотрите в файле dlpp3.zip

Рассмотрим Delphi код для создания записи в Favorites («Избранное»)

Пример для записи в «Избранное» Internet Explorer (папка Favorites) можно посмотреть здесь http://delphiworld.narod.ru/base/webbrowser_add_to_fav.html.

Напишем более простой код. Добавим его в процедуру TForm1.Button1Click

procedure TForm1.Button1Click(Sender: TObject);  
begin  
Reg := TRegistry.Create;  
Reg.RootKey:=HKEY_CURRENT_USER;  
Reg.OpenKey('SoftwareMicrosoftWindowsCurrentVersionExplorerShell Folders',true);  
Form1.Caption:= '' + Reg.ReadString('Favorites') + '' + 'Zagranica.url';  
ee:= Reg.ReadString('Favorites') + '' + 'Hello.url';  
Reg.CloseKey;  
Reg.Destroy;  
  
Form1.Caption:= ee;  
  
//Создать новую запись в Favorites  
//C:Documents and SettingsAdministratorFavorites  
  
AssignFile(f, ee);  
Rewrite(f); // Создать и открыть файл  
writeln(f, '[DEFAULT]');  
writeln(f, 'BASEURL= http://www.geocities.com/aboutsoft/');  
writeln(f, '[InternetShortcut]');  
writeln(f, 'URL= http://www.geocities.com/aboutsoft/');  
writeln(f, 'Modified=70037C581883C001A1');  
CloseFile(f); // Закрыть файл  
  
end;  

Полный Delphi проект программы смотрите в файле dlpp4.zip

В принципе, здесь создан еще один коммерчески ориентированный продукт. Представьте себе веб-сайт-каталог тематических ссылок. Например список ссылок на mp3 музыкальные сайты. Используя приведенный выше VB код, можно создать такой каталог тематических ссылок на компьютере, в Favorites. Создается вложенная папка, например, «MP3 ссылки». И в неё помещаются записи с ссылками на тщательно проверенные каталоги MP3 музыки. Программа для создания таких каталогов – вполне коммерческий продукт. Новый продукт. Эта ниша на рынке еще не занята. Кроме того, программа может быть немного усовершенствована и получать обновления списка вебсайтов с вебстраницы разработчика. Технически, это очень просто.

6. Wallpapers – рекламные обои
В предыдущем руководстве программиста показано, что обои (оформление рабочего стола) тоже могут использоваться в рекламных технологиях

procedure TForm1.Button1Click(Sender: TObject);  
 var  
   Picture: TPicture;  
   Desktop: TCanvas;  
   X, Y: Integer;  
 begin  
   // Objekte erstellen   
  // create objects   
  Picture := TPicture.Create;  
   Desktop := TCanvas.Create;  
  
   // Bild laden   
  // load bitmap   
  Picture.LoadFromFile('bitmap1.bmp');  
  
   // Geratekontex vom Desktop ermitteln   
  // get DC of desktop   
  Desktop.Handle := GetWindowDC(0);  
  
   // Position des Bildes   
  // position of bitmap   
  X := 100;  
   Y := 100;  
  
   // Bild zeichnen   
  // draw bitmap   
  Desktop.Draw(X, Y, Picture.Graphic);  
  
   // Geratekontex freigeben   
  ReleaseDC(0, Desktop.Handle);  
  
   // Objekte freigeben   
  // release objects   
  Picture.Free;  
   Desktop.Free;  
 end;  

Пример можно посмотреть здесь http://delphiworld.narod.ru/base/bmp_to_desktop.html

Обратите внимание, что графический файл для Desktop должен быть в формате .bmp

7. Об эффективности
Эффективность использования программ-прединсталляторов чрезвычайно высока. Свыше 70% программ инсталлируются сразу после скачивания и без всякого анализа состава программного пакета. В лучшем случае читается файл ReadMe.txt

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

Работа с файлами

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

Сегодня текстовые файлы.
Текстовый файл отличается тем что он разбит на разные по длине строки, отделенные символами #13#10. Есть 2 основных метода работы с текстовыми файлами — старый паскалевский способ и через файловые потоки. У обоих есть преимущества и недостатки. Через потоки способ проще поэтому начнем с него.

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

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

Исходный код:

Memo1.lines.loadfromfile('c:\MyFile.txt');  

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

Исходный код:

Memo1.lines.savetoFile('c:\MyFile.txt');  

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

Исходный код:

Function ReadFromFile(FileName:string):string;  
begin  
 With TStringList.create do  
   try  
     LoadFromFile(FileName);  
     result:=text;  
   finally  
     Free;  
   end;  
end;  

Часть II

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

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

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

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

Исходный код:

var f:TextFile;  

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

Исходный код:

AssignFile(F, 'c:\MyFile.txt');  

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

Исходный код

Rewrite(f);  

— файл есть и его надо открыть для чтения (с первой строки)

Исходный код

Reset(f);  

— файл есть и его надо открыть для дописования строк в конец

Исходный код

Append(f);  

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

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

Исходный код

CloseFile(f);  

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

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

Исходный код

ReadLn(f,s)  

— будет прочитанна текущая строка и позиция чтения переведена на следующую позицию.

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

Исходный код:

While not eof(f) do  
 begin  
   ReadLn(f, s);  
   {здесь делаем ÷то-то с про÷итанной строкой}  
 end;  

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

Исходный код:

var  Canceled:Boolean;  
  
Function GetFileSize(FIleName:String):integer;  
 var f: File of Byte;  
begin  
 try  
   AssignFile(f, FileName);  
   Reset(f);  
   result:=filesize(F);  
   CloseFile(f);  
 except  
   result:=-1;  
 end;  
end;  
  
  
Procedure ReadMyFile;  
Var i,j:integer;  
Begin  
  ProgressBar1.Max:=GetFileSize('c:\MyFile.txt');  
  ProgressBar1.position:=0;  
  assignfile(f,'c:\MyFile.txt');  
  Canceled:=False;  
  reset(f);  
     i:=0;j:=0;  
     while not eof(f) do  
       begin  
         inc(j);  
         readln(f,s);  
         i:=i+length(s)+2;  
         if (j mod 1000)=0 then  
           begin  
             ProgressBar1.position:=i;  
             Application.ProcessMessages;  
             if canceled then break;  
           end;  
         {здесь мы ÷то-то делаем с про÷итанной строкой}  
       end;  
     CloseFile(f);  
End;  

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

Часть III

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

Type MyRec=Record  
          Name:string[100];  
          Age:byte;  
          Membership:Boolean;  
          Accounts:array[1..10] of integer;  
       End;  

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

Var MyVar:MyRec;  

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

Var f:File of MyRec;  

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

AssignFile(f,'c:\MyFile.rec');  
Rewrite(f);  
MyVar.Name:='Vitaly';  
MyVar.Age:=33;  
MyVar.Membership:=True;  
MyVar.Accounts[1]:=12345;  
MyVar.Accounts[2]:=34985;  
Write(f,MyVar);  
Closefile(f);  

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

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

Исходный код:

var  
 FromF, ToF: file;  
 NumRead, NumWritten: Integer;  
 Buf: array[1..2048] of Char;  
begin  
 if OpenDialog1.Execute then                               { Display Open dialog box }  
 begin  
   AssignFile(FromF, OpenDialog1.FileName);  
   Reset(FromF, 1); { Record size = 1 }  
   if SaveDialog1.Execute then                              { Display Save dialog box}  
   begin  
     AssignFile(ToF, SaveDialog1.FileName); { Open output file }  
     Rewrite(ToF, 1); { Record size = 1 }  
     Canvas.TextOut(10, 10, 'Copying ' + IntToStr(FileSize(FromF))  
       + ' bytes...');  
     repeat  
       BlockRead(FromF, Buf, SizeOf(Buf), NumRead);  
       BlockWrite(ToF, Buf, NumRead, NumWritten);  
     until (NumRead = 0) or (NumWritten <> NumRead);  
       CloseFile(FromF);  
       CloseFile(ToF);  
   end;  
 end;  
end;  

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

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

Erase(f) — удаляет файл
FilePos(f) — возвращает текущую позицию чтения/записи в файл
Flush(f) — сбрасывает кэшированные файловые операции на диск
Rename(f, ‘MyNewFileName.txt’) — переименование файлов
Truncate(f) — файл обрезается до текущей позиции чтения/записи
Теперь разберем возможности работы потомка TStream — TFileStream — файловый поток. Этот класс был специально введен для работы с файлами. Для работы с файловым потоком Вам надо записать в Uses модули classes, Sysutils (classes — включает в себя собственно определение класса, Sysutils — некоторые константы необходимые для работы).

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

Исходный код:

Procedure WriteFileUsingStream(s, FileName:string);  
begin  
 with TFileStream.create(FileName, fmCreate or fmOpenWrite) do  
   try  
     write(pointer(s)^,length(s));  
   finally  
     free;  
   end;  
end;  

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

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

fmCreate = $FFFF;  
fmOpenRead       = $0000;  
fmOpenWrite      = $0001;  
fmOpenReadWrite  = $0002;  
fmShareCompat    = $0000;  
fmShareExclusive = $0010;  
fmShareDenyWrite = $0020;  
fmShareDenyRead  = $0030;  
fmShareDenyNone  = $0040;  

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

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

Исходный код:

 var p:PChar;  
begin  
 GetMem(p, 255);  
 with TFileStream.create('c:\myText.txt', fmOpenReadWrite) do  
   try  
     Seek(10,soFromBeginning);  
     read(p^, 254);  
   finally  
     free;  
   end;  
 showmessage(p);  
 FreeMem(p);  
end;  

И пояснения к коду:
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 на файл и работу через него. Тут есть 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; — функции для работы с атрибутами файлов. Вот список возможных атрибутов:
faReadOnly $00000001 Read-only files
faHidden $00000002 Hidden files
faSysFile $00000004 System files
faVolumeID $00000008 Volume ID files
faDirectory $00000010 Directory files
faArchive $00000020 Archive files
faAnyFile $0000003F Any file
(Естественно не все атрибуты применимы во всех случаях)

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

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

Исходный код:

Type TFileInfo=record  
                Exists:boolean;//true если файл найден  
                Name:String; //имя файла с расширением  
                ShortName:String;//DOS 8.3 имя файла  
                NameNoExt:String;//имя файла без расширения  
                Extension:string;//расширение файла  
                AssociatedFile:string;//программа с которой ассоциирован файл  
                Path:string;// путь к файлу  
                ShortPath:string;// DOS 8.3 путь файла  
                Drive:string;// дисковод на котором находится файл  
                CreateDate:TDateTime; //время когда файл создан  
                Size:Int64;// размер файла (работает для файлов и больше 2Gb)  
                Attributes:record //нали÷ие/отсутствие системных атрибутов  
                             ReadOnly:boolean;  
                             Hidden:boolean;  
                             System:boolean;  
                             Archive:boolean;  
                           end;  
                ModifyDate:TDateTime; //время последнего изменения файла  
                LastAccessDate:TDateTime; //дата последнего открытия  
              end;  
  
  
Function ReadFileInfo(FileName:string):TFileInfo;  
var ts:TSearchRec;  
  
  Function FileTime2DateTime(FT:_FileTime):TDateTime;  
  var FileTime:_SystemTime;  
  begin  
     FileTimeToLocalFileTime(FT, FT);  
     FileTimeToSystemTime(FT,FileTime);  
     Result:=EncodeDate(FileTime.wYear, FileTime.wMonth, FileTime.wDay)+  
             EncodeTime(FileTime.wHour, FileTime.wMinute, FileTime.wSecond, FileTime.wMilliseconds);  
  end;  
  
  Function AssociatedFile(FileExt:string):string;  
    var key:string;  
  begin  
    With TRegistry.create do  
      try  
        RootKey:=HKEY_CLASSES_ROOT;  
        OpenKey(FileExt, false);  
        Key:=ReadString('');  
        CloseKey;  
        OpenKey(key+'\Shell\open\command', false);  
        result:=ReadString('');  
        Closekey;  
      finally  
        free;  
      end  
  end;  
  
begin  
 Result.Name:=ExtractFileName(FileName);  
 Result.Extension:=ExtractFileExt(FileName);  
 Result.NameNoExt:=Copy(Result.Name,1,length(Result.Name)-length(Result.Extension));  
 Result.Path:=ExtractFilePath(FileName);  
 Result.Drive:=ExtractFileDrive(FileName);  
 Result.ShortPath:=ExtractShortPathName(ExtractFilePath(FileName));  
 if lowercase(Result.Extension)<>'.exe' then Result.AssociatedFile:=AssociatedFile(Result.Extension);  
 if FindFirst(FileName, faAnyFile, ts)=0 then  
   begin  
 Result.Exists:=true;  
     Result.CreateDate:=FileDateToDateTime(ts.Time);  
  
Result.Size:=ts.FindData.nFileSizeHigh*4294967296+ts.FindData.nFileSizeLow;  
     Result.Attributes.ReadOnly:=(faReadOnly and ts.Attr)>0;  
     Result.Attributes.Hidden:=(faHidden and ts.Attr)>0;  
     Result.Attributes.System:=(faSysFile and ts.Attr)>0;  
     Result.Attributes.Archive:=(faArchive and ts.Attr)>0;  
     Result.ModifyDate:=FileTime2DateTime(ts.FindData.ftLastWriteTime);  
     Result.LastAccessDate:=FileTime2DateTime(ts.FindData.ftLastAccessTime);  
     Result.ShortName:=ts.FindData.cAlternateFileName;  
     Findclose(ts);  
   end  
 else Result.Exists:=false;  
end;  

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

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

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

Исходный код:

Var SearchRec:TSearchRec;  
...  
  If FindFirst('c:\Windows\*.*', faAnyFile, SearchRec)=0 then  
     repeat  
        {Вот здесь мы можем делать с найденным файлом ÷то угодно 
         SearchRec.name - имя файла 
         ExpandFileName(SearchRec.name) - имя файла с полным путем}  
     until FindNext(SearchRec) <> 0;  
     FindClose(SearchRec);  

Примечания по приведенному коду:
1) Первыми в список могут попадать файлы с именами «.» и «..» — это ДОСовские имена для переходов на «родительский уровень», иногда нужна обработка для их игнорирования.
2) FindFirst в качестве первого параметра принимает шаблон для поиска, так как он был принят для ДОС. Если шаблон не включает путь то файлы будут искаться в текущем каталоге.
3) FindFirst требует задания атрибута для файла — здесь мы искали все файлы, если надо какие-то определенные (например только скрытые, или только каталоги) то надо это указать, список всех атрибутов я уже приводил выше.
4) SearchRec переменная связывает во едино FindFirst и FindNext, но требует ресурсов для своей работы, поэтому желательно ее освободить после поиска процедурой FindClose(SearchRec) — на самом деле утечки памяти небольшие, но если программа работает в цикле и долгое время пожирание ресурсов будет значительным.
5)FindFirst/FindNext — работают не открывая файлы, поэтому они корректно находят даже Swap файлы Windows…

Поиск файлов на винчестере

Хотя я и не очень хороший «Делфер», но я очень люблю программировать в Delphi, делать маленькие полезные программки для себя и своего компьютера. Недавно я узнал как производить поиск файлов на компьютере, причем поиск файлов производится не в отдельном каталоге, а на всем винчестере и в процессе поиска возможно следить за поиском. Процедуре поиска я нашел очень широкое применение, например, у меня на компьютере имеется папка с исходниками по Delphi и в этой папки очень много лишних файлов, которые занимают место на винчестере и при помощи процедуры поиска я удаляю ненужные файлы (*.cfg; *.~dfm; *.~pas и др.).

Начнем с описания процедуры FindResursive( Const path: String; Const mask: String) где переменная Path — каталог в котором будет производится поиск (‘c:’), а Mask — название файла или его часть (‘*.exe’ или ‘*.*’ или ‘project.dpr’).

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

Procedure FindRecursive( Const path: String; Const mask: String);  
  Var  
    fullpath: String;  
  Function Recurse( Var path: String; Const mask: String ): Boolean;  
    Var  
      SRec: TSearchRec;  
      retval: Integer;  
      oldlen: Integer;  
    Begin  
      Recurse := True;  
      oldlen := Length( path );  
      retval := FindFirst( path+mask, faAnyFile, SRec );  
      While retval = 0 Do Begin  
        If (SRec.Attr and (faDirectory or faVolumeID)) = 0 Then  
        form1.ListBox1.items.Add(path+srec.name);  
        retval := FindNext( SRec );  
      End;  
      FindClose( SRec );  
      If not Result Then Exit;  
      retval := FindFirst( path+'*.*', faDirectory, SRec );  
      While retval = 0 Do Begin  
        If (SRec.Attr and faDirectory) <> 0 Then  
          If (SRec.Name <> '.') and (SRec.Name <> '..') Then Begin  
            path := path + SRec.Name + '';  
            If not Recurse( path, mask ) Then Begin  
              Result := False;  
              Break;  
            End;  
            Delete( path, oldlen+1, 255 );  
          End;  
        retval := FindNext( SRec );  
      End;  
      FindClose( SRec );  
    End; { Recurse }  
  Begin  
    If path = '' Then  
      GetDir(0, fullpath)  
    Else  
      fullpath := path;  
    If fullpath[Length(fullpath)] <> '' Then  
      fullpath := fullpath + '';  
    If mask = '' Then  
      Recurse( fullpath, '*.*' )  
    Else  
      Recurse( fullpath, mask );  
  End;  

В целом же программа выглядит так:

unit Unit1;  
  
interface  
  
uses  
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  
  Dialogs, StdCtrls;  
  
type  
  TForm1 = class(TForm)  
    ListBox1: TListBox;  
    Button1: TButton;  
    procedure Button1Click(Sender: TObject);  
  private  
    { Private declarations }  
  public  
    { Public declarations }  
  end;  
  
var  
  Form1: TForm1;  
  
implementation  
  
{$R *.dfm}  
Procedure FindRecursive( Const path: String; Const mask: String);  
  Var  
    fullpath: String;  
  Function Recurse( Var path: String; Const mask: String ): Boolean;  
    Var  
      SRec: TSearchRec;  
      retval: Integer;  
      oldlen: Integer;  
    Begin  
      Recurse := True;  
      oldlen := Length( path );  
      retval := FindFirst( path+mask, faAnyFile, SRec );  
      While retval = 0 Do Begin  
        If (SRec.Attr and (faDirectory or faVolumeID)) = 0 Then  
        form1.ListBox1.items.Add(path+srec.name); {добавление}  
        {очередного найденного файла в ListBox}  
       {-------------------------------------}  
       {здесь можно производить слежением за выполнение процедуры}  
       {например, поставить ProgressBar}  
        retval := FindNext( SRec );  
      End;  
      FindClose( SRec );  
      If not Result Then Exit;  
      retval := FindFirst( path+'*.*', faDirectory, SRec );  
      While retval = 0 Do Begin  
        If (SRec.Attr and faDirectory) <> 0 Then  
          If (SRec.Name <> '.') and (SRec.Name <> '..') Then Begin  
            path := path + SRec.Name + '';  
            If not Recurse( path, mask ) Then Begin  
              Result := False;  
              Break;  
            End;  
            Delete( path, oldlen+1, 255 );  
          End;  
        retval := FindNext( SRec );  
      End;  
      FindClose( SRec );  
    End; { Recurse }  
  Begin  
    If path = '' Then  
      GetDir(0, fullpath)  
    Else  
      fullpath := path;  
    If fullpath[Length(fullpath)] <> '' Then  
      fullpath := fullpath + '';  
    If mask = '' Then  
      Recurse( fullpath, '*.*' )  
    Else  
      Recurse( fullpath, mask );  
  End;  
  
  
procedure TForm1.Button1Click(Sender: TObject);  
begin  
FindRecursive('d:','*.*'); {вместо 'd:' можно написать лубой каталог}  
end;  

Автор: Михаил Христосенко

Поиск файлов на Delphi

В этой статье мы познакомимся с функциями для поиска файлов на дисках Вашего (и не только :) компьютера. Для тех кто собирается писать вирусы или что-то подобное используя приведенный алгоритм, то предупреждаю: создание вредоносных программ карается по УК РФ!!! Так что думайте сами, а тем кому интересно как же найти файл на диске с помощью Дельфи, то читайте дальше…

Для поиска файлов на диске в Delphi существует две функции, первая из них — это FindFirst, ниже приведено ее описание:

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

Path — путь, по которому искать файл, включая его имя и расширение (возможно использовать символ *).

attr — атрибуты файла. Может принимать следующие значения:

faReadOnly $00000001 Только чтение
faHidden $00000002 Скрытый
faSysFile $00000004 Системный
faVolumeID $00000008 Метка диска
faDirectory $00000010 Директория
faArchive $00000020 Обычный
faAnyFile $0000003F Любой файл

F- переменная типа TsearchRec, в нее Delphi запихивает все характеристики найденного файла. Описание типа TsearchRec (предлагаю только для того, чтобы было проще освоиться, сам тип уже описан в SysUtils).

type  
    TSearchRec = record  
    Time: Integer; // время создания  
    Size: Integer; //размер файла в байтах  
    Attr: Integer; // Атрибуты  
    Name: TFileName; //имя файла  
    ExcludeAttr: Integer;   
    FindHandle: THandle; //хандл на файл  
    FindData: TWin32FindData; //доп. информация о файле  
end;  

Теперь приведу простой пример использования этой функции. Поставьте на форму одну кнопку TButton, а обработчик события OnClick у нее должен иметь примерно такой вид:

procedure TForm1.Button1Click(Sender: TObject);  
 var sr:TSearchRec;  
 begin  
 findFirst('*.exe',faAnyFile,sr);  
 edit1.Text:=sr.Name;  
 end;  

Чтобы искать следующий такой же файл, надо написать FindNext (Sr); Если файл найден, то процедуры FindFirst и FindNext возвращают 0 (зеро).

Ну а теперь собственно о том, как можно применить эти функции на практике, то есть опять пример!!! Чтобы разобраться с использованием этих функций попробуем написать программку, которая выдавала список всех программ с расширением *.exe в указанной директории, а затем при нажатии на кнопку включалась бы выбранная программа. На примере я покажу, как найти все .exe файлы в директории Windows, а затем объясню как можно модифицировать программку!

Итак, ставим на форму компонент TListBox в него мы будем выводить список найденных файлов. Обработчик события OnClick для нашей первой кнопки заменяем на такой:

procedure TForm1.Button1Click(Sender: TObject);  
var sr:TSearchRec;  
Result:word;  
begin  
    ChDir('C:windows');//меняем папку на C:Windows  
    Result := FindFirst ('*.exe',faAnyFile,sr);  
    ListBox1.Clear;  
    While result=0 do  
Begin  
    Result:=FindNext (sr);  
    ListBox1.Items.add(sr.name);  
End;  
end;  

Как видите мы просто организовали цикличный проход по директории C:Windows, который прекращается, как только функции возвращает не ноль! Функция ChDir была использована для смены папки с текущей на папку C:windows

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

У меня расширенная процедура поиска выглядит вот так:

procedure ffind(cat:string); //каталог, откуда начать поиск  
var sea:TSearchRec;  
res:integer; //результат поиска (0 или нет)  
begin  
res:=FindFirst(cat+'*.*',faAnyFile,sea); //ищем первый файл  
res:=findNext(sea);//ищем следующий файл  
While res=0 do  
begin  
if (Sea.Attr=faDirectory) and ((Sea.Name='.')or(Sea.Name='..')) then//чтобы не было файлов . и..  
begin  
Res:=FindNext(sea);  
Continue;//продолжаем цикл  
end;  
  
if (Sea.Attr=faDirectory) then//если нашли директорию, то ищем файлы в ней  
begin  
Ffind(cat+Sea.Name+'');//рекурсивно вызываем нашу процедуру  
Res:=FindNext(Sea);//ищем след. файл  
Continue;//продолжаем цикл  
end;  
form1.ListBox1.Items.Add(Sea.Name);//добавляем в Listbox:Tlistbox имя файла  
Res:=FindNext(Sea);//ищем след. файл  
end;  
FindClose(Sea);//освобождаем пересенную поиска  
end;  

Здесь была использована процедура FindClose(var sea: TsearchRec); она необходима для освобождения поисковой переменной. В следующих примерах ее я использовать не буду, но Вы имейте ее в виду!!!

Возможно, этот алгоритм не самый быстрый и удобный, но он работает.
Для того, чтобы ваше приложение не выглядело подвисшим, можно добавить Application.ProcessMessages в начало нашей процедуры.

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

procedure TForm1.Button2Click(Sender: TObject);  
begin  
    WinExec(pchar(listbox1.Items[listbox1.itemindex]),sw_show);  
end;  

Поскольку файлы находятся в директории Windows, то при вызове метода WinExec путь к файлам можно не указывать, а если вы используете какую-либо другую директорию, то вызов метода WinExec должен быть примерно таким:

WinExec(pchar('C:Путь к вашей папке'+listbox1.Items[listbox1.itemindex]),sw_show);   

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

DirectoryListBox1.Directory  

Поэтому в обработчике первой кнопки нужно убрать вызов функции ChDir. А в обработчике второй кнопки вставить приведенную выше конструкцию.

Таким образом приведу полный код приложения, которое получилось у меня с использованием компонента DirectoryListBox

unit Unit1;  
  
interface  
  
uses  
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,  
StdCtrls, FileCtrl;  
  
type  
TForm1 = class(TForm)  
Edit1: TEdit;  
Button1: TButton;  
ListBox1: TListBox;  
Button2: TButton;  
DirectoryListBox1: TDirectoryListBox;  
procedure Button1Click(Sender: TObject);  
procedure Button2Click(Sender: TObject);  
private  
{ Private declarations }  
public  
{ Public declarations }  
end;  
  
var  
Form1: TForm1;  
  
implementation  
  
{$R *.DFM}  
  
procedure TForm1.Button1Click(Sender: TObject);  
var sr:TSearchRec;  
Result:word;  
begin  
Result := FindFirst ('*.exe',faAnyFile,sr);  
ListBox1.Clear;  
While result=0 do  
Begin  
Result:=FindNext (sr);  
ListBox1.Items.add(sr.name);  
End;  
end;  
  
procedure TForm1.Button2Click(Sender: TObject);  
begin  
WinExec(pchar(DirectoryListBox1.Directory+''+listbox1.Items[listbox1.itemindex]),sw_show);  
end;  
  
end.  

Ну вот и все :)) Надеюсь, что помог Вам своими рассуждениями и примерами!

Автор: Михаил Христосенко

Копирование файлов

В данной статье показаны некоторые методы копирования файлов. Существуют и готовые функции — CopyFile(), CopyFileEx(), но порой они неприменимы. Например, при использовании функции CopyFile() с большими файлами мы не имеем доступа к процессу копирования, т.е. программа на некоторое время просто «зависает». Из методов, приведённых ниже, только первый позволяет контроллировать процесс копирования — можно добавить прогресс-индикатор выполнения или отображать объём скопированных данных.

1. Копирование методом Pascal

type   
  TCallBack=procedure (Position,Size: Longint); {Для индикации процесса копирования}   
   
procedure FastFileCopy(Const InfileName, OutFileName: String; CallBack: TCallBack);   
const BufSize = 3*4*4096; { 48Kbytes дает прекрасный результат }   
type   
  PBuffer = ^TBuffer;   
  TBuffer = array [1..BufSize] of Byte;   
var   
  Size             : integer;   
  Buffer           : PBuffer;   
  infile, outfile  : File;   
  SizeDone,SizeFile: Longint;   
begin   
  if (InFileName <> OutFileName) then   
  begin   
    buffer := Nil;   
    AssignFile(infile, InFileName);   
    System.Reset(infile, 1);   
    try   
      SizeFile := FileSize(infile);   
      AssignFile(outfile, OutFileName);   
      System.Rewrite(outfile, 1);   
      try   
        SizeDone := 0; New(Buffer);   
        repeat   
          BlockRead(infile, Buffer^, BufSize, Size);   
          Inc(SizeDone, Size);   
          CallBack(SizeDone, SizeFile);   
          BlockWrite(outfile,Buffer^, Size)   
        until Size < BufSize;   
        FileSetDate(TFileRec(outfile).Handle,   
        FileGetDate(TFileRec(infile).Handle));   
      finally   
        if Buffer <> Nil then Dispose(Buffer);   
        System.Close(outfile)   
      end;   
    finally  
      System.Close(infile);   
    end;   
  end  
else   
  Raise EInOutError.Create('File cannot be copied into itself');   
end;  

2. Копирование методом потока.

procedure FileCopy(Const SourceFileName, TargetFileName: String);  
var  
  S,T: TFileStream;  
begin  
  S := TFileStream.Create(sourcefilename, fmOpenRead);  
  try  
    T := TFileStream.Create(targetfilename, fmOpenWrite or fmCreate);  
    try  
      T.CopyFrom(S, S.Size);  
      FileSetDate(T.Handle, FileGetDate(S.Handle));  
    finally  
      T.Free;  
    end;  
  finally  
    S.Free;  
  end;  
end;  

3. Копирование методом LZExpand

uses LZExpand;  
   
procedure CopyFile(FromFileName, ToFileName  : string);  
var  
  FromFile, ToFile: File;  
begin  
  AssignFile(FromFile, FromFileName);  
  AssignFile(ToFile, ToFileName);  
  Reset(FromFile);  
  try  
    Rewrite(ToFile);  
    try  
    if LZCopy(TFileRec(FromFile).Handle, TFileRec(ToFile).Handle) < 0 then  
      raise Exception.Create('Error using LZCopy')  
    finally  
      CloseFile(ToFile);  
    end;  
  finally  
    CloseFile(FromFile);  
  end;  
end;  

4. Копирование методами Windows

uses ShellApi;  
   
function WindowsCopyFile(FromFile, ToDir : string) : boolean;  
var F : TShFileOpStruct;  
begin  
  F.Wnd := 0; F.wFunc := FO_COPY;  
  FromFile:=FromFile+#0; F.pFrom:=pchar(FromFile);  
  ToDir:=ToDir+#0; F.pTo:=pchar(ToDir);  
  F.fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION;  
  Result:=ShFileOperation(F) = 0;  
end;  
   
// Пример копирования:  
procedure TForm1.Button1Click(Sender: TObject);  
begin  
  if not WindowsCopyFile('C:UTILARJ.EXE', GetCurrentDir) then  
    ShowMessage('Copy Failed');  
end;  

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

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

Копирование и удаление файлов в Delphi

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

В самом простом случае вопрос копирования файлов очень прост (хотя поступило много пожеланий рассказать именно об этом)! Для этого достаточно посмотреть в хелп по Delphi :))

Копирование файлов
В Delphi есть функция CopyFile. Вот ее описание из хелпа

BOOL CopyFile(
  LPCTSTR lpExistingFileName, // pointer to name of an existing file 
  LPCTSTR lpNewFileName, // pointer to filename to copy to 
  BOOL bFailIfExists // flag for operation if file exists 
);

Параметры передаваемые в эту функцию:

Указатель на имя существующего файла (нуль терминированная строка т.е. тип PChar! )
Указатель на имя файла, который будет создан/перезаписан после копирования (нуль терминированная строка т.е. тип PChar! )
Если этот параметр True и файл с таким именем уже существует, то функция вернет False. Если же файл, с именем указанным во втором параметре существует и в качестве третьего параметра передан False — то функция перезапишет файл и благополучно завершится.
Приведу небольшой пример использования этой функции. Создайте на диске C: файл ‘1.txt’, а на форму поставьте кнопку:

procedure TForm1.Button1Click(Sender: TObject);  
begin  
  if CopyFile('c:1.txt','c:2.txt',true) then  
  ShowMessage('Файл успешно скопирован!')  
  else ShowMessage('Неудача!');  
end;  

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

procedure TForm1.Button1Click(Sender: TObject);  
begin  
  if CopyFile('c:1.txt','c:2.txt',true) then  
    ShowMessage('Файл успешно скопирован!')  
  else  
    ShowMessage('Ошибка! Вот ее код: '+IntToStr(GetLastError));  
end;  

Таким образом нажав второй раз на кнопку мы получим сообщение: «Ошибка! Вот ее код: 80». Это говорит нам, что файл существует.

Коды всех ошибок можно легко найти в хелпе.

Для углубления рассматриваемого вопроса приведу пример копирования файлов с помощью файлового потока (TFileStream). В приведенной пользовательской функции введены два дополнительных параметра From и Count, которые указывают, соответственно, с какого и по какой байт нужно копировать файл. Если необходимо скопировать весь файл, то необходимо передать нули. Вот код этой функции:

function MyCopyFile( InFile,OutFile: String; From,Count: Longint ): Longint;  
var  
  InFS,OutFS: TFileStream;  
begin  
  InFS := TFileStream.Create( InFile, fmOpenRead );//создаем поток  
  OutFS := TFileStream.Create( OutFile, fmCreate );//создаем поток  
  InFS.Seek( From, soFromBeginning );//перемещаем указатель в From  
  Result := OutFS.CopyFrom( InFS, Count );  
  InFS.Free;//освобождаем  
  OutFS.Free;//освобождаем  
end;  

Удаление файлов
Для удаления файлов в Delphi так же предусмотрена специальная процедура DeleteFile. В качестве параметра, передаваемого в функцию, выступает строка типа PChar, указывающая имя файла, который нужно удалить. Сразу предлагаю Вам простой пример на использование этой функции:

procedure TForm1.Button1Click(Sender: TObject);  
begin  
  if DeleteFile('c:2.txt') then  
    ShowMessage('Файл успешно удален!')  
  else  
  ShowMessage('Ошибка! Вот ее код: '+IntToStr(GetLastError));  
end;  

Удаление пустой директории
Чтобы удалить пустую директорию с помощью Delphi достаточно обратиться к функции RemoveDir.

function RemoveDir(const Dir: string): Boolean;  

Эта функция возвращает True если директория, указанная в единственном параметре, передаваемом в функцию, успешно удалена, в противном случае функция возвратит False.

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

function MyRemoveDir(sDir : String) : Boolean;   
var   
  iIndex : Integer;   
  SearchRec : TSearchRec;   
  sFileName : String;   
begin   
  Result := False;   
  sDir := sDir + '*.*';   
  iIndex := FindFirst(sDir, faAnyFile, SearchRec);   
  
  while iIndex = 0 do begin   
    sFileName := ExtractFileDir(sDir)+''+SearchRec.Name;   
    if SearchRec.Attr = faDirectory then begin   
      if (SearchRec.Name <> '' ) and   
      (SearchRec.Name <> '.') and   
      (SearchRec.Name <> '..') then   
        MyRemoveDir(sFileName);   
      end else begin   
        if SearchRec.Attr <> faArchive then   
        FileSetAttr(sFileName, faArchive);   
        if NOT DeleteFile(sFileName) then   
        ShowMessage('Could NOT delete ' + sFileName);   
    end;   
    iIndex := FindNext(SearchRec);   
  end;   
  
  FindClose(SearchRec);   
  
  RemoveDir(ExtractFileDir(sDir));   
  Result := True;   
end;  

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

procedure TForm1.Button1Click(Sender: TObject);  
begin  
  if MyRemoveDir('C:testDir') then ShowMessage('Директория успешно удалена')  
  else ShowMessage('Не получается удалить директорию');  
end;  

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

if FileExists('c:1.txt') then  
 if CopyFile('c:1.txt','c:2.txt',true) then  
  ShowMessage('Файл успешно скопирован!')  

Чтобы использовать в функциях CopyFile и DeleteFile имена файлов полученные с помощью, например, OpenDialog, надо из привести к типу PChar:

if CopyFile(Pchar(OpenDialog1.FileName),Pchar(SaveDialog1.FileName),true) then ...  

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

Автор: Михаил Христосенко

Как прочитать ID3-Tag’и из MP3-файла?

На самом деле, как это не кажется, прочитать ID3-теги из MP3-файла совсем не сложно и, более того, для этого не требуется никаких специальных компонентов. TMediaPlayer здесь также бессилен. Все ID3-теги хранятся в последних 128-ми байтах MP3-файла. Часть из них записана не в том виде, в каком мы привыкли их читать в Winamp или в другом проигрывателе… Итак, перейдём сразу к коду…

{   
  Byte 1-3 = ID 'TAG'   
  Byte 4-33 = Titel / Title   
  Byte 34-63 = Artist   
  Byte 64-93 = Album   
  Byte 94-97 = Jahr / Year   
  Byte 98-127 = Kommentar / Comment   
  Byte 128 = Genre   
}  

Это — общая схема хранения информации в MP3-файле, которую мы будем читать. Вся эта информация отделяется от «музыкальной» части файла символами ‘TAG’ . После них и начинается служебная информация: название композиции, исполнитель, альбом, год исполнения, комментарий, жанр. Будет гораздо проще работать с ID3-тегами, объявив для них отдельный тип:

type    
  TID3Tag = record    
    ID: string[3];    
    Titel: string[30];    
    Artist: string[30];    
    Album: string[30];    
    Year: string[4];    
    Comment: string[30];    
    Genre: Byte;    
  end;  

Итак, мы объявили тип TID3Tag и теперь можем его использовать. Как видно из кода, этот класс содержит несколько строковых полей, в каждом из которых и будет записан соответствующий ID3-тег.

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

const   
 Genres : array[0..146] of string =    
    ('Blues','Classic Rock','Country','Dance','Disco','Funk','Grunge',    
    'Hip- Hop','Jazz','Metal','New Age','Oldies','Other','Pop','R&B',    
    'Rap','Reggae','Rock','Techno','Industrial','Alternative','Ska',    
    'Death Metal','Pranks','Soundtrack','Euro-Techno','Ambient',    
    'Trip-Hop','Vocal','Jazz+Funk','Fusion','Trance','Classical',    
    'Instrumental','Acid','House','Game','Sound Clip','Gospel','Noise',    
    'Alternative Rock','Bass','Punk','Space','Meditative','Instrumental Pop',    
    'Instrumental Rock','Ethnic','Gothic','Darkwave','Techno-Industrial','Electronic',    
    'Pop-Folk','Eurodance','Dream','Southern Rock','Comedy','Cult','Gangsta',    
    'Top 40','Christian Rap','Pop/Funk','Jungle','Native US','Cabaret','New Wave',    
    'Psychadelic','Rave','Showtunes','Trailer','Lo-Fi','Tribal','Acid Punk',    
    'Acid Jazz','Polka','Retro','Musical','Rock & Roll','Hard Rock','Folk',    
    'Folk-Rock','National Folk','Swing','Fast Fusion','Bebob','Latin','Revival',    
    'Celtic','Bluegrass','Avantgarde','Gothic Rock','Progressive Rock',    
    'Psychedelic Rock','Symphonic Rock','Slow Rock','Big Band','Chorus',    
    'Easy Listening','Acoustic','Humour','Speech','Chanson','Opera',    
    'Chamber Music','Sonata','Symphony','Booty Bass','Primus','Porn Groove',    
    'Satire','Slow Jam','Club','Tango','Samba','Folklore','Ballad',    
    'Power Ballad','Rhytmic Soul','Freestyle','Duet','Punk Rock','Drum Solo',    
    'Acapella','Euro-House','Dance Hall','Goa','Drum & Bass','Club-House',    
    'Hardcore','Terror','Indie','BritPop','Negerpunk','Polsk Punk','Beat',    
    'Christian Gangsta','Heavy Metal','Black Metal','Crossover','Contemporary C',    
    'Christian Rock','Merengue','Salsa','Thrash Metal','Anime','JPop','SynthPop');  

Наконец, процедура, читающая все теги из MP3-файла… Пропишем её в разделе implementation:

var    
  Form1: TForm1;    
   
implementation    
   
{$R *.dfm}    
   
function readID3Tag(FileName: string): TID3Tag;    
var    
  FS: TFileStream;    
  Buffer: array [1..128] of Char;    
begin    
  FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);    
  try    
    FS.Seek(-128, soFromEnd);    
    FS.Read(Buffer, 128);    
    with Result do    
    begin    
      ID := Copy(Buffer, 1, 3);    
      Titel := Copy(Buffer, 4, 30);    
      Artist := Copy(Buffer, 34, 30);    
      Album := Copy(Buffer, 64, 30);    
      Year := Copy(Buffer, 94, 4);    
      Comment := Copy(Buffer, 98, 30);    
      Genre := Ord(Buffer[128]);    
    end;    
  finally    
    FS.Free;    
  end;    
end;  

Данная функция возвратит нам всё содержимое ID3-тегов MP3-файла, указанного в FileName. Теперь дело за малым — написать обработчик открытия файла и чтения содержимого всех тегов из выбранного файла:

procedure TfrmMain.Button1Click(Sender: TObject);    
begin    
  IF OpenDialog1.Execute then    
  begin    
    WITH readID3Tag(OpenDialog1.FileName) do    
    begin    
      LlbID.Caption := 'ID: ' + ID;    
      LlbTitel.Caption := 'Titel: ' + Titel;    
      LlbArtist.Caption := 'Artist: ' + Artist;    
      LlbAlbum.Caption := 'Album: ' + Album;    
      LlbYear.Caption := 'Year: ' + Year;    
      LlbComment.Caption := 'Comment: ' + Comment;    
      IF (Genre >= 0) AND (Genre <=146) then    
       LlbGenre.Caption := 'Genre: ' + Genres[Genre]    
      else    
       LlbGenre.Caption := 'N/A';    
    end;    
  end;    
end;  

Ну вот и всё… Добавьте соответствующие компоненты на форму и испробуйте работоспособность кода. В архиве с данной статьёй есть данная демо-программа.

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

Работа с CSV файлами в Delphi

Введение
CSV-файл – простейший по организации файл-таблица, который понимает Microsoft Excel. CSV – Como Separated Value – данные, разделенные запятой. Это обычный текстовый файл, в котором каждая строка олицетворяет ряд таблицы, а разделение этого ряда на колонки осуществляется путем разделения значений специальным разделителем. Обычно роль этого разделителя, судя из названия, играет запятая. Однако, встречается и другой разделитель – точка с запятой. Даже в Microsoft не определились, с каким разделителем должен работать Excel. При сохранении какой-либо таблицы в формате CSV, в качестве разделителя используется точка с запятой. Но, при открытии такого файла с помощью Microsoft Excel, нужно быть очень внимательным, так как, не знаю, шутка это или нет, существует, как Вы знаете два способа открытия файла:

В главном меню программы выбрать пункт «Открыть» из меню «файл».
Найти на жестком диске нужный файл и два раза кликнуть на нем мышкой.
Так вот, при открытии CSV файла первым способом, Excel использует точку с запятой в качестве разделителя, а при открытии вторым способом Excel использует запятую в качестве разделителя. Правда в Microsoft Excel XP эта проблема(?) решена, и используется только точка с запятой, не смотря на название файла.

Работа с CSV файлами в Delphi
Для работы с CSV-файлами в Delphi Вам не понадобятся различные сторонние компоненты. Как я уже говорил, CSV-файл – это обычный текстовый файл. Следовательно, для работы с ним мы будем использовать стандартный тип TextFile определенный в модуле system.

Давайте напишем процедуру для загрузки CSV файла в таблицу TStringGrid. Это стандартный компонент Delphi для работы со строковыми таблицами. Находится он на странице Additional в палитре компонентов Delphi.

Вот код этой процедуры:

procedure LoadCSVFile (FileName: String; separator: char);  
var f: TextFile;  
    s1, s2: string;  
    i, j: integer;  
begin  
 i := 0;  
 AssignFile (f, FileName);  
 Reset(f);  
 while not eof(f) do  
 begin  
   readln (f, s1);  
   i := i + 1;  
   j := 0;  
   while pos(separator, s1)<>0 do  
    begin  
     s2 := copy(s1,1,pos(separator, s1)-1);  
     j := j + 1;  
     delete (s1, 1, pos(separator, S1));  
     StringGrid1.Cells[j-1, i-1] := s2;  
    end;  
   if pos (separator, s1)=0 then  
    begin  
     j := j + 1;  
     StringGrid1.Cells[j-1, i-1] := s1;  
    end;  
   StringGrid1.ColCount := j;  
   StringGRid1.RowCount := i+1;  
  end;  
 CloseFile(f);  
end;  

Теперь разберем этот код.

procedure LoadCSVFile (FileName: String; separator: char);  

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

AssignFile (f, FileName);  
Reset(f);  

Здесь мы ассоциируем с файловой переменной f имя файла и открываем его для чтения.

while not eof(f) do  
  begin  
   readln (f, s1);  

Пока не достигнут конец файла, читаем из него очередную строку.

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

while pos(separator, s1)<>0 do  
 begin  
  s2 := copy(s1,1,pos(separator, s1)-1);  
  j := j + 1;  
  delete (s1, 1, pos(separator, S1));  
  StringGrid1.Cells[j-1, i-1] := s2;  
 end;  
if pos (separator, s1)=0 then  
 begin  
  j := j + 1;  
  StringGrid1.Cells[j-1, i-1] := s1;  
 end;  
StringGrid1.ColCount := j;  
StringGRid1.RowCount := i+1;  

Ну вот, пожалуй, и все что я хотел написать.

Пишем компонент — окно выбора папки

Среди стандартных диалогов Delphi 6 (вкладка Dialogs) диалог выбора папки, как это не прискорбно, отсутствует. Но ничего, сейчас мы исправим данное упущение, написав соответствующий компонент.

Чтобы создать новый компонент, в Delphi IDE выберите пункт File > New > Other и затем в появившемся окне нажмите New Component. Появится диалоговое окно, в котором:

Ancensor type (класс-предок нового компонента) — введите TComponent;
Class Name (имя нового класса) — TBrowseFolderDlg;
Palette Page (имя вкладки: поместим наш диалог вместе со стандартными дельфийскими) — Dialogs.
Остальное оставьте без изменений и нажмите OK. Наш мегадиалог будет вызываться функцией, продекларированной в Public Declarations компонента:

function BrowseFolder(title: PChar; h: hwnd): String;  

Где title — заголовок диалога (поставьте любой на ваш вкус), h — хэндл окна-владельца (то есть вашей программы). А команды, использованные в коде, содержатся в ShlObj.pas, так что не забудьте указать этот модуль в разделе uses.

unit BrowseFolderDlg;  
   
interface  
   
uses  
Windows, Messages, SysUtils, Classes, Controls, ShlObj;  
   
type  
  TBrowseFolderDlg = class(TComponent)  
  private  
    { Private declarations }  
  protected  
    { Protected declarations }  
  public  
    { Public declarations }  
    function BrowseFolder(title: PChar; h: hwnd): String;  
  published  
    { Published declarations }  
end;  
   
procedure Register;  
   
implementation  
   
procedure Register;  
begin  
  RegisterComponents('Dialogs', [TBrowseFolderDlg]);  
end;  
   
function TBrowseFolderDlg.BrowseFolder(title: PChar; h: hwnd): String;  
var  
  lpItemID: PItemIDList;  
  path: array[0..Max_path] of char; //выбранная папка  
  BrowseInfo: TBrowseInfo; //настройки диалога  
begin  
  FillChar(BrowseInfo, sizeof(TBrowseInfo), #0);  
  SHGetSpecialFolderLocation(h,csidl_desktop,BrowseInfo.pidlRoot);  
  //устанавливаем свойства диалогового окна  
  with BrowseInfo do  
    begin   
    hwndOwner := h; //окно-владелец  
    lpszTitle := title; //заголовок диалога  
    //не показываем некоторые системные папки: "Корзина", "Панель управления" и т.д  
    ulFlags := BIF_RETURNONLYFSDIRS+BIF_EDITBOX+BIF_STATUSTEXT;  
  end;  
  //выводим диалог  
  lpItemID := SHBrowseForFolder(BrowseInfo);  
  //папка, указанная юзером, существует?  
  if lpItemId <> nil then  
    begin   
    SHGetPathFromIDList(lpItemID, Path);  
    result:=path;  
    GlobalFreePtr(lpItemID); //освобождаем ресурсы  
  end;  
end;  
   
end.  

Готово? Сохранитесь и, выбрав Component > Install Component, проинсталлируйте наш диалог, указав в разделе Unit File Name путь к файлу BrowseFolderDlg.pas.

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

procedure TForm1.Button1Click(Sender: TObject);  
begin  
  Form1.Caption:= 'Выбрана следующая папка: '+  
  BrowseFolderDlg1.BrowseFolder('Укажите каталог:',Application.Handle);  
end;  

Конечно, это только «скелет» полноценного компонента, и просторы для модернизации безграничны.

Работаем с файлами

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

Копирование файлов в Delphi
За копирование файлов в Delphi отвечает функция CopyFile, она имеет следующий синтаксис:

CopyFile(Начальный_файл, Конечный_файл, Перезапись);  

Где,
Начальный_файл — Полный путь с указанием имени и расширения к файлу, который будет копироваться.
Конечный_файл — Полный путь с указанием имени и расширения куда копируем.
Перезапись – Если такой файл уже существует, то будет ли он перезаписан (true — не будет, false — будет).

Пример:

CopyFile('C:1.txt', 'D:1.txt', true);  

Обратите внимание, что при указании второго параметра (Конечный_файл) мы указываем не просто папку куда хотим скопировать файл, но и еще желаемое имя с расширение файла. Т.е если Начальный файл c:1.txt, то если указать имя конечного файла как d:1Copy.txt то в процессе копирования наш 1.txt переименуется в 1Copy.txt.

Переименование файлов в Delphi
За переименование файлов в Delphi отвечает функция RenameFileсинтаксис у неё очень простой и чем то схож с функцией копирования.

RenameFile('Начальное_имя','Конечное_имя') 

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

Пример:

RenameFile('c:1.txt','c:1Rename.txt');  

Перемещение файлов в Delphi
Что бы переместить файл, в Delphi используется функция MoveFile. Давайте посмотрим на её синтаксис:

MoveFile(Начальный_файл, Конечный_файл); 

Где,
Начальный_файл — Полный путь с указанием имени и расширения к файлу, который будет перемещаться.
Конечный_файл — Полный путь с указанием имени и расширения куда перемещаем.

Здесь также следует обратить внимание на то что при указании второго параметра (Конечный_файл) мы указываем не просто папку куда хотим переместить файл, но и еще желаемое имя с расширение файла. Т.е если Начальный файл c:1.txt, то если указать имя конечного файла как d:1Paste.txt то в процессе перемещения наш 1.txt переименуется в 1Paste.txt.

Удаление файлов в Delphi
Наверное, самая простая из рассмотренных выше функций это функция удаления, DeleteFile.

DeleteFile('Имя_файла');  

Имя_файла — здесь предполагается указание полного пути, имени и расширения удаляемого файла.

Пример:

DeleteFile('c:1.txt');  

Последовательный поиск

Для понимания этой статьи вам будет достаточно базовых знаний о программировании баз данных в Delphi.

Основная форма проекта должна содержать компоненты TTable и TEdit (назовем его edtSearch). Заметим, что таблица, к которой прикреплен компонент TTable, должна быть проиндексирована по полю, в котором производится поиск.

Компонент TTable содержит несколько методов для поиска заданного значения в таблице. Это методы Goto, GoToKey, GoToNearest, Find, FindKey, Find Nearest и другие (описание этих методов смотрите в помощи). Добавим обработчик события OnChange для компонента TEdit:

procedure TForm1.edtSearchChange(Sender: TObject);  
begin  
  with Table1 do begin  
    SetKey;  
    FieldByName('Company').AsString:=edtSearch.text;  
    GotoNearest;  
  end;  
end;  

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

Теперь можно немного усложнить обработчик onChange. Например, можно отключить обработчик, если пользователь нажимает Backspace или Delete, или поле ввода не содержит текста. Выглядеть это будет примерно так:

procedure TForm1.edtSearchChange(Sender: TObject);  
var txt, sfind:string;  
      len:integer;  
begin  
  //don't do anything if user presses  
  //delete or backspace  
  if edFromCode = true then begin  
    edFromCode := false;  
    exit;  
  end;  
  
  //don't do anything if there is  
  //no text in edSearch  
  txt:=edtSearch.Text;  
  if Length(txt)=0 then exit;  
  
  //goto nearest match  
  with Table1 do begin  
    SetKey;  
    FieldByName('Company').AsString:=edtSearch.text;  
    GotoNearest;  
  end;  
  
  //calculate what part of text should be selected  
  sfind := Table1.FieldByName('Company').AsString;  
  len := Length(sfind) - Length(txt);  
  if len > 0 then begin  
    edFromCode:=true;  
    edtSearch.Text:=sfind;  
    edtSearch.SelStart:=Length(txt);  
    edtSearch.SelLength:=len;  
  end;  
end;  

Для такого случая нужен дополнительный код — обработчик события onKeyDown:

procedure TForm1.edtSearchKeyDown(Sender: TObject; var Key: Word;  
                Shift: TShiftState);  
begin  
  if (Key=VK_DELETE) or (Key=VK_BACK) then begin  
    if Lenght(edtSearch.Text)>0 then begin  
    //onchange event should not be executed...  
      edFromCode := true;  
    end;  
  end;  
end;   

Вставка Bitmap через буфер обмена

function CopyClipToBuf(DC: HDC; Left, Top,  
           Width, Height: Integer;  Rop: LongInt;  
           var CopyDC: HDC;  
           var CopyBitmap: HBitmap): Boolean;  
var  
  TempBitmap: HBitmap;  
begin  
  Result := False;  
  CopyDC := 0;  
  CopyBitmap := 0;  
  if DC <> 0 then  
    begin  
      CopyDC := CreateCompatibleDC(DC);  
      if CopyDC <> 0 then  
        begin  
          CopyBitmap := CreateCompatibleBitmap(DC,  
                          Width, Height);  
          if CopyBitmap <> 0 then  
            begin  
              TempBitmap := CopyBitmap;  
              CopyBitmap := SelectObject(CopyDC,  
                              CopyBitmap);  
              Result := BitBlt(CopyDC, 0, 0,  
                          Width, Height, DC,  
                          Left, Top, Rop);  
              CopyBitmap := TempBitmap;  
            end;  
        end;  
    end;  
end;  
  
function CopyBufToClip(DC: HDC; var CopyDC: HDC;  
           var CopyBitmap: HBitmap;   
           Left, Top, Width, Height: Integer;  
           Rop: LongInt; DeleteObjects: Boolean): Boolean;  
var  
  TempBitmap: HBitmap;  
begin  
  Result := False;  
  if (DC <> 0) and  
     (CopyDC <> 0) and  
     (CopyBitmap <> 0) then  
    begin  
      TempBitmap := CopyBitmap;  
      CopyBitmap := SelectObject(DC, CopyBitmap);  
      Result := BitBlt(DC, Left, Top,  
                  Width, Height, CopyDC,  
                  0, 0, Rop);  
      CopyBitmap := TempBitmap;  
      if DeleteObjects then  
        begin  
          DeleteDC(CopyDC);  
          DeleteObject(CopyBitmap);  
        end;  
    end;  
end;  

Учимся копировать файлы в Delphi

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

Способ номер РАЗ

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

procedure MyFileCopy(Const SourceFileName, TargetFileName: String);  

Нажимаем Ctrl+Shift+C как всегда Delphi сгенерирует заготовку для нашей процедуры, посмотри что в итоге получилось у меня и допиши недостающие строчки у себя

procedure MyFileCopy(Const SourceFileName, TargetFileName: String);  
var  
A,F : TFileStream;  
begin  
A := TFileStream.Create(sourcefilename, fmOpenRead );  
try  
F := TFileStream.Create(targetfilename, fmOpenWrite or fmCreate);  
try  
F.CopyFrom(A, A.Size ) ;  
FileSetDate(F.Handle, FileGetDate(A.Handle));  
finally  
F.Free;  
end;  
finally  
A.Free;  
end;  
end;   

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

Myfilecopy('D:index.htm', 'D:11.html' );  

Способ номер ДВА

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

CopyFile(Pchar('D:index.txt'), Pchar('D:11.txt'), true)   

На этом всё встретимся в следующих уроках!

Файловые операции с использованием стандартного диалога с анимацией Копирование Файлов

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

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

uses ShellAPI;  
  
procedure TForm1.Button1Click(Sender: TObject);   
var   
  Fo      : TSHFileOpStruct;   
  buffer  : array[0..4096] of char;   
  p       : pchar;   
begin   
  FillChar(Buffer, sizeof(Buffer), #0);   
  p := @buffer;   
  p := StrECopy(p, 'C:DownLoad1.ZIP') + 1;   
  p := StrECopy(p, 'C:DownLoad2.ZIP') + 1;   
  p := StrECopy(p, 'C:DownLoad3.ZIP') + 1;   
  StrECopy(p, 'C:DownLoad4.ZIP');   
  FillChar(Fo, sizeof(Fo), #0);   
  Fo.Wnd    := Handle;   
  Fo.wFunc  := FO_COPY;   
  Fo.pFrom  := @Buffer;   
  Fo.pTo    := 'D:';   
  Fo.fFlags := 0;   
  if ((SHFileOperation(Fo) <> 0) or  
    (Fo.fAnyOperationsAborted <> false)) then  
    ShowMessage('Cancelled')   
end;  

>
Как получить список всех файлов в папке

  • Подписаться на тему
  • Сообщить другу
  • Скачать/распечатать тему



Сообщ.
#1

,
07.12.03, 01:07

    Как получить список всех файлов в определённой директории ?


    Vit



    Сообщ.
    #2

    ,
    07.12.03, 02:47

      А в FAQ заходить не пробовали?


      Song



      Сообщ.
      #3

      ,
      07.12.03, 05:18

        Go to FAQ

        Master

        Chow



        Сообщ.
        #4

        ,
        27.04.04, 11:52

          Ошибки в Факе на эту тему. :huh:

          Вот та процедура, что там предлагается:

          ExpandedWrap disabled

            Procedure ScanDir(StartDir: String; Mask:string; List:TStrings);

            { Процедура выводит список директории в список List, начиная с директории, указанной в StartDir. Mask — маска для получения файлов

            Источник delphi.mastak.ru

            © А. Подгорецкий }

            Var SearchRec : TSearchRec;

            Begin

             IF Mask =» then Mask:= ‘*.*’;

             IF StartDir[Length(StartDir)] <> » then StartDir := StartDir + »;

              IF FindFirst(StartDir+Mask, faAnyFile, SearchRec) = 0 then

               Begin

                Repeat

                   { Чтобы выполнение «не подвисало» }

                 Application.ProcessMessages;

                 IF (SearchRec.Attr and faDirectory) <> faDirectory then

                    List.Add(StartDir + SearchRec.Name) else

                     IF (SearchRec.Name <> ‘..’) and (SearchRec.Name <> ‘.’) then

                   Begin

                     List.Add(StartDir + SearchRec.Name + »);

                       { Рекурсивный вызов }

                     ScanDir(StartDir + SearchRec.Name + »,Mask,List);

                   End;

                Until FindNext(SearchRec) <> 0;

                FindClose(SearchRec);

              End; {IF}

            end;

          Ошибка 1:

          ExpandedWrap disabled

                 IF (SearchRec.Attr and faDirectory) <> faDirectory then

          Это еще что за условие? Оно ж ВСЕГДА выполнятся будет.

          Ошибка 2:
          Если задать маску отличную от *.* — то не найдется ни одно вложение в подпапках, так как имена папок тоже фильтрируются по этой маске.


          Генерал



          Сообщ.
          #5

          ,
          27.04.04, 12:46

            Junior

            *

            Рейтинг (т): 1

            Цитата Chow @ 27.04.04, 14:52

            Ошибка 1:

            ExpandedWrap disabled

                   IF (SearchRec.Attr and faDirectory) <> faDirectory then

            Это еще что за условие? Оно ж ВСЕГДА выполнятся будет.

            faDirectory — это атрибут директории (типа папка)
            и если в атрибуте присутствует атрибут faDirectory , то такие варианты исключаются…т.е. папки не будут указываться в списке…

            Master

            Chow



            Сообщ.
            #6

            ,
            27.04.04, 13:08

              Сори. Тормознул, наверное, малёха. :(
              Тут побитное and, а не логическое, да?
              (в С++ есть разница & и && — соответственно).

              ОК. Ну, а на счет маски? Может тоже все нормально в ФАКЕ — просто я чего-то туплю?… :wacko:


              Генерал



              Сообщ.
              #7

              ,
              27.04.04, 15:45

                Junior

                *

                Рейтинг (т): 1

                Цитата Chow @ 27.04.04, 16:08

                Цитата

                Если задать маску отличную от *.* — то не найдется ни одно вложение в подпапках, так как имена папок тоже фильтрируются по этой маске.

                ОК. Ну, а на счет маски? Может тоже все нормально в ФАКЕ — просто я чего-то туплю?… :wacko:

                если задашь маску *.* — то выберутся все файлы из всех папок и подпапок…
                если задашь *.txt, то выберуться только текстовые файлы…ну и т.д.

                сами папки в список не попадут, т.к. мы их отсеяли атрибутом, а маской отсееваем по именам…


                Vestnik



                Сообщ.
                #8

                ,
                27.04.04, 17:47

                  Junior

                  *

                  Рейтинг (т): 2

                  Есессно получу минус в рейтинге, но в очередной раз удивляет реакция ( во времени) уже не модератора, а администратора Song-а
                  С уважением


                  Song



                  Сообщ.
                  #9

                  ,
                  27.04.04, 17:50

                    Vestnik, когда я писал своё сообщение я не видел сообщения Vit’а. Вот в чём секрет.

                    Guru

                    Miscђka



                    Сообщ.
                    #10

                    ,
                    28.04.04, 02:05

                      Цитата

                      Song, 27.04.04, 23:50
                      я не видел сообщения Vit’а

                      А можно поподробнее? Почему у вас время ответа такое разное? А не первый раз замечаю, что сообщений друг друга не видите :) Просто интересно.

                      Master

                      Chow



                      Сообщ.
                      #11

                      ,
                      28.04.04, 05:48

                        Цитата

                        Генерал, 27.04.04, 18:45
                        если задашь маску *.* — то выберутся все файлы из всех папок и подпапок…
                        если задашь *.txt, то выберуться только текстовые файлы…

                        … только из ТЕКУЩЕЙ папки.
                        Все файлы из подпапок текущей папки не попадают. Т.к. маска *.txt фильтрирует не только список файлов, но и список папок (папки тоже ш могут иметь расширение).

                        Коротче: постараюсь доделать сам. Просто поднял топик, что-бы обратить внимание на возможную ошибку в ФАКе.


                        Генерал

                          


                        Сообщ.
                        #12

                        ,
                        28.04.04, 08:08

                          Junior

                          *

                          Рейтинг (т): 1

                          Цитата Chow @ 28.04.04, 08:48

                          Цитата

                          Генерал, 27.04.04, 18:45
                          если задашь маску *.* — то выберутся все файлы из всех папок и подпапок…
                          если задашь *.txt, то выберуться только текстовые файлы…

                          … только из ТЕКУЩЕЙ папки.
                          Все файлы из подпапок текущей папки не попадают. Т.к. маска *.txt фильтрирует не только список файлов, но и список папок (папки тоже ш могут иметь расширение).

                          если встречается папка, то программа вызывает саму себя для этой подпапки и поиск идёт уже в подпапке..вот тут:

                          Цитата

                          { Рекурсивный вызов }
                          ScanDir(StartDir + SearchRec.Name + »,Mask,List);

                          …и т.д., пока не просмотрит все подпапки…

                          так что в факе всё прально…

                          Master

                          Chow



                          Сообщ.
                          #13

                          ,
                          28.04.04, 08:32

                            Цитата

                            Генерал, 28.04.04, 11:08
                            если встречается папка, то программа вызывает саму себя для этой подпапки и поиск идёт уже в подпапке..вот тут:

                            В том то и дело, что папка НЕ встречается, т.к. не удовлетворяет маску *.txt

                            ExpandedWrap disabled

                              IF FindFirst(StartDir+Mask, faAnyFile, SearchRec) = 0 then

                            Например я задам StartDir = ‘C:Temp’, а Mask = ‘*.txt’. Процедура найдет все тхт-файлы лишь в папке C:Temp. А если в этой папке будут подпапки:
                            C:Temp1
                            C:Temp2.txt
                            C:Temp3
                            то она заглянет лишь в C:Temp2.txt, а C:Temp1 и C:Temp3 пропустит, т.к. они не удовлетворяют условию поиска.


                            Генерал

                              


                            Сообщ.
                            #14

                            ,
                            28.04.04, 09:19

                              Junior

                              *

                              Рейтинг (т): 1

                              сначала анализируется атрибут:

                              Цитата

                              IF (SearchRec.Attr and faDirectory) <> faDirectory then

                              если это не папка (<> faDirectory), то это файл (естесно), и если у него расширение .тхт, то он попадает в список:

                              Цитата

                              List.Add(StartDir + SearchRec.Name

                              если это папка, то выполняется сначала проверка, системная ли это папка:

                              Цитата

                              IF (SearchRec.Name <> ‘..’) and (SearchRec.Name <> ‘.’

                              если не системная, то программа вызывает саму себя, а в качестве папки задаёт подпапку:

                              Цитата

                              { Рекурсивный вызов }
                              ScanDir(StartDir + SearchRec.Name + »,Mask,List);

                              ну вот, вроде всё разжевал и по полочкам разложил… :D

                              Master

                              Chow



                              Сообщ.
                              #15

                              ,
                              28.04.04, 09:30

                                Цитата

                                Генерал, 28.04.04, 12:19
                                ну вот, вроде всё разжевал и по полочкам разложил…

                                А реально попробовать? :D

                                Самое первое условие не проходит:

                                ExpandedWrap disabled

                                    IF FindFirst(StartDir+Mask, faAnyFile, SearchRec) = 0 then

                                если, например, в папке C:Temp нету ни одного файла, а только подпапки в которых есть уже файлы.


                                Генерал

                                  


                                Сообщ.
                                #16

                                ,
                                28.04.04, 09:38

                                  Junior

                                  *

                                  Рейтинг (т): 1

                                  Цитата Chow @ 28.04.04, 12:30

                                  А реально попробовать? :D

                                  вот теперь тебе осталось сесть и реально пробывать…и ответы на свои вопросы найдёшь!
                                  …можешь есчо книжечку по дельфи почитать…там тоге всё хорошо написано… :D

                                  Master

                                  Chow



                                  Сообщ.
                                  #17

                                  ,
                                  28.04.04, 10:05

                                    Это был мой совет вам, на счет попробовать.
                                    Сам я уже давно попробовал — поэтому и поднял топик.


                                    Генерал

                                      


                                    Сообщ.
                                    #18

                                    ,
                                    28.04.04, 10:53

                                      Junior

                                      *

                                      Рейтинг (т): 1

                                      всё работает1
                                      вот уж не поленился, поставил на форму кнопочку и ListBox…
                                      скопировал программку из фака, которую ты выложил…один к одному…
                                      давлю на кнопочку… а в листбоксе — чудо!…. список всех файлов из папки, которую я задал!…ну и из всех попдпапок соответственно! :D

                                      Master

                                      Chow



                                      Сообщ.
                                      #19

                                      ,
                                      28.04.04, 11:11

                                        Цитата

                                        Генерал, 28.04.04, 13:53
                                        список всех файлов

                                        А по маске?


                                        Anatoly Podgoretsky



                                        Сообщ.
                                        #20

                                        ,
                                        28.04.04, 11:25

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

                                          В моем FAQ есть иакая процедура поиск файла по маске во всех папках по маске *.*.
                                          http://podgoretsky.com/ftp/Language/nps/ru.delphi.html#N158


                                          Song



                                          Сообщ.
                                          #21

                                          ,
                                          28.04.04, 14:35

                                            Цитата

                                            Mischka, 28.04.04, 06:05
                                            А можно поподробнее? Почему у вас время ответа такое разное? А не первый раз замечаю, что сообщений друг друга не видите Просто интересно.

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


                                            Генерал

                                              


                                            Сообщ.
                                            #22

                                            ,
                                            28.04.04, 16:37

                                              Junior

                                              *

                                              Рейтинг (т): 1

                                              Цитата Chow @ 28.04.04, 14:11

                                              Цитата

                                              Генерал, 28.04.04, 13:53
                                              список всех файлов

                                              А по маске?

                                              Chow!
                                              Сделай вот так:

                                              Цитата

                                              Procedure ScanDir(StartDir,Mask: String; List: TStrings);
                                              Var SearchRec: TSearchRec;
                                              Begin
                                              IF Mask=»then Mask:=’*.*’;
                                              IF StartDir[Length(StartDir)]<>»then StartDir := StartDir + »;
                                              // Сначала находим и печатаем все файлы из
                                              // главной папки по маске Mask
                                              List.Add(StartDir);
                                              IF FindFirst(StartDir+Mask,faAnyFile,SearchRec)=0 then Repeat
                                              IF(SearchRec.Attr and faDirectory)<>faDirectory then
                                              List.Add(StartDir+SearchRec.Name);
                                              Until FindNext(SearchRec)<>0;
                                              // Теперь находим все подпапки и продолжаем в них поиск
                                              IF FindFirst(StartDir+’*.*’,faAnyFile,SearchRec)=0 then Repeat
                                              IF((SearchRec.Attr and faDirectory)=faDirectory)and
                                              ((SearchRec.Name<>’..’)and(SearchRec.Name <> ‘.’))then
                                              ScanDir(StartDir+SearchRec.Name+»,Mask,List);
                                              Until FindNext(SearchRec)<>0;
                                              FindClose(SearchRec);
                                              end;

                                              и будет тебе счастье! :rolleyes:


                                              Vit



                                              Сообщ.
                                              #23

                                              ,
                                              29.04.04, 12:34

                                                Коды в FAQ — это не библиотека, которую можно бездумно подключить и использовать, это только направление в котором думать надо. Простейший пошаговый проход кода с просмотром на каждой строки переменных легко решает все Ваши вопросы. Люди старались попридумывали в Дельфи клавиши — F7, F8, Shift-F7, Ctrl-F5, Ctrl-F7, F4 — вот и надо их использовать, развели демагогию на десяток топиков — а ведь тот код преобразовать под свои нужды работа минут на 10, да разбираться в нём не фиг делать, достаточно ПРОСТО ПОШАГОВО ЕГО ВЫПОЛНИТЬ!

                                                Master

                                                Chow



                                                Сообщ.
                                                #24

                                                ,
                                                29.04.04, 14:14

                                                  Vit, полностью согласен.
                                                  Так и сделал с самого начала. Тем более, что я итак переводил все на С++, так что не разобравшись — сделать было бы такой перевод трудно. А поднял топик потому, что подумал что в коде из ФАКа была ошибка (оказалось не ошибка, а я просто криво на С++ перевел :)) и… вообще потом пожалел что поднял… :)

                                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)

                                                  0 пользователей:

                                                  • Предыдущая тема
                                                  • Delphi: Общие вопросы
                                                  • Следующая тема

                                                  [ Script execution time: 0,0575 ]   [ 16 queries used ]   [ Generated: 28.05.23, 02:58 GMT ]  

                                                  Понравилась статья? Поделить с друзьями:

                                                  Не пропустите также:

                                                • Как найти итальянского собеседника
                                                • Как найти объем усеченного цилиндра
                                                • Как найти диагональ ромба онлайн
                                                • Как найти век через год
                                                • Как найти число элементов выборки

                                                • 0 0 голоса
                                                  Рейтинг статьи
                                                  Подписаться
                                                  Уведомить о
                                                  guest

                                                  0 комментариев
                                                  Старые
                                                  Новые Популярные
                                                  Межтекстовые Отзывы
                                                  Посмотреть все комментарии