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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
unit iconchanger; {shaped by shapeless} interface uses windows; type PICONDIRENTRYCOMMON = ^ICONDIRENTRYCOMMON; ICONDIRENTRYCOMMON = packed record bWidth : Byte; // Width, in pixels, of the image bHeight : Byte; // Height, in pixels, of the image bColorCount : Byte; // Number of colors in image (0 if >=8bpp) bReserved : Byte; // Reserved ( must be 0) wPlanes : Word; // Color Planes wBitCount : Word; // Bits per pixel dwBytesInRes : DWord; // How many bytes in this resource? end; PICONDIRENTRY = ^ICONDIRENTRY; ICONDIRENTRY = packed record common : ICONDIRENTRYCOMMON; dwImageOffset : DWord; // Where in the file is this image? end; PICONDIR = ^ICONDIR; ICONDIR = packed record idReserved : Word; // Reserved (must be 0) idType : Word; // Resource Type (1 for icons) idCount : Word; // How many images? idEntries : ICONDIRENTRY; // An entry for each image (idCount of 'em) end; PGRPICONDIRENTRY = ^GRPICONDIRENTRY; GRPICONDIRENTRY = packed record common : ICONDIRENTRYCOMMON; nID : Word; // the ID end; PGRPICONDIR = ^GRPICONDIR; GRPICONDIR = packed record idReserved : Word; // Reserved (must be 0) idType : Word; // Resource type (1 for icons) idCount : Word; // How many images? idEntries : GRPICONDIRENTRY; // The entries for each image end; function UpdateApplicationIcon(srcicon : PChar; destexe : PChar) : Boolean; implementation function UpdateApplicationIcon(srcicon : PChar; destexe : PChar) : Boolean; var hFile : Integer; id : ICONDIR; pid : PICONDIR; pgid : PGRPICONDIR; uRead : DWord; nSize : DWord; pvFile : PByte; hInst : LongInt; begin result := False; hFile := CreateFile(srcicon, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if hFile > 0 then begin ReadFile(hFile, id, sizeof(id), uRead, nil); SetFilePointer(hFile, 0, nil, FILE_BEGIN); GetMem(pid, sizeof(ICONDIR) + sizeof(ICONDIRENTRY)); GetMem(pgid, sizeof(GRPICONDIR) + sizeof(GRPICONDIRENTRY)); ReadFile(hFile, pid^, sizeof(ICONDIR) + sizeof(ICONDIRENTRY), uRead, nil); move(pid^, pgid^, sizeof(GRPICONDIR)); pgid^.idEntries.common := pid^.idEntries.common; pgid^.idEntries.nID := 1; nSize := pid^.idEntries.common.dwBytesInRes; GetMem(pvFile, nSize); SetFilePointer(hFile, pid^.idEntries.dwImageOffset, nil, FILE_BEGIN); ReadFile(hFile, pvFile^, nSize, uRead, nil); CloseHandle(hFile); hInst:=BeginUpdateResource(destexe, False); if hInst > 0 then begin UpdateResource(hInst, RT_ICON, MAKEINTRESOURCE(1), LANG_NEUTRAL, pvFile, nSize); EndUpdateResource(hInst, False); result := True; end; FreeMem(pvFile); FreeMem(pgid); FreeMem(pid); end; end; end. |
Moduł ten umożliwia zmianę ikony pliku exe, działa na wszystkich prawie execach 😉 krzaczy się tylko na specjalnie modyfikowanych plikach etc. Ikonke zmieniamy funkcją UpdateApplicationIcon, pierwszy parametr to sciezka do ikony, a drugi do pliku .exe Mam nadzieje, że komuś się to przyda.
Zaznaczam ze kod nie jest mojego autorstwa.
Poniższy artykuł przedstawia w jaki sposób wyszukiwać pliki na dysku według podanej maski, czasu utworzenia czy rozmiaru
Wyszukiwanie plików w Delphi opiera się o rekord TSearchRec. Jego budowa przedstawia się następująco:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
type TSearchRec = record Time: Integer; Size: Integer; Attr: Integer; Name: TFileName; ExcludeAttr: Integer; FindHandle: THandle; FindData: TWin32FindData; end; |
Tłumaczenie parametrów :
Time – data utworzenia
Size – rozmiar pliku
Attr – atrybuty pliku :
faReadOnly – Tylko do odczytu
faHidden – Ukryty
faSysVolume – Systemowy
faArchive – Zarchiwizowany
faAnyFile – Zwykły plik
faDirectory – Katalog
faVolumeID – Etykieta
FindHandle – znaleziony uchwyt
FindData – zawiera informacje o pliku:
dwFileAttributes – Atrybuty pliku
ftCreateionTime – Data utworzenia
ftLastWriteTime – Data ostatniej modyfikacji
ftLastAccessTime – Data ostatniego korzystania z pliku
Do wyszukania pliku posłużymy się poleceniem FindFirst np.
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 26 27 28 29 |
var Info : TSearchRec; Znaleziono : Integer; begin Znaleziono := FindFirst('C:*.*', faAnyFile, Info); while (Znaleziono = 0) do begin ListBox1.Items.Add('C:' + Info.Name); // zapisujemy nazwę znalezionego pliku Znaleziono := FindNext(Info); // szukamy następnego end; FindClose(Info); // kończymy szukanie end; |
Pierwsza zmienna polecenia FindFirst określa ścieżkę i maskę pliku, druga określa atrybut pliku, a trzecia nasz Rekord, nazwałem go Info. Zmienna znaleziono informuje nas o liczbie plików o podanych przez nas parametrach znalezionych na dysku. Polecenie FindNext umożliwia dalsze przeszukiwanie pliku. Aby ograniczyć wyniki wyszukiwania do plików np. o określonym rozmiarze musimy dodać warunek :
1 2 3 4 5 6 7 |
... If Info.Size = XXX then ListBox1.Items.Add('C:' + Info.Name); ... |
Oki doki, dzisiaj postaram się pokazać jak w prosty sposób zrobić plik podobny do archiwum np. zipa czy rara. Wprawdzie w naszym formacie nie będziemy stosowali kompresji (aby niepotrzebnie na początek nie komplikować) ale pokaże jedno z możliwych podejść do tego zagadnienia. Na początek może napisze po krótce do czego może się przydać taki plik, otóż można w nim trzymać np. spakowane levele do gry, save gamy, mapy oraz inne zasoby do programów. Ok, koniec marudzenia, co będziemy potrzebowali do szczęścia ?
1. Podstawy programowania obiektowego.
2. Podstawy wiadomości o strumieniach.
3. kilka minut czasu aby przeczytać i zrozumieć.
Na początek, trzeba się zastanowić jaka będzie wewnętrzna struktura naszego archiwum ? Ja wybrałem bardzo prosty układ, pliki w archiwum są przechowywane kolejno w następującej postaci:
Rozmiar nazwy[int], nazwa[tablica bajtów], rozmiar danych[int], dane plik[tablica bajtów]
Jakie są główne plusy:
1. Prosta budowa pliku.
2. Łatwość dodawania kolejnych danych
minusy:
1. Czasochłonne usuwanie plików z archiwum.
2. Czasochłonna zmiana kolejności plików w archiwum.
3. Aby uzyskać listę plików trzeba przeskanować całe archiwum.
Jak widać jest więcej minusów jak plusów, ale w moim przypadku przeważyła dla mnie prostota pliku, poza tym kasowanie/reorganizacja archiwum nie są zbyt częstymi operacjami więc nie były dla mnie dużym minusem.
Ok. wiemy już, co chcemy oraz jakimi środkami to uzyskamy, teraz wypisze metody, które zaimplementowałem w naszej klasie obsługującej archiwum, i opisze z grubsza (szczegóły można zrozumieć analizując dołączony kod) idee działania tych metod:
1 |
constructor Create(const filename:String; const Mode: Word); |
Tworzymy nasze archiwum, w zależności od trybu mode (patrz TFileStream + F1), tworzymy nowe archiwum lub otwieramy już istniejące. Inicjujemy wewnętrznego streama który będzie obsługiwał nasz plik.
1 |
destructor Destroy;override; |
Bez komentarza 😉
1 |
procedure PrepareFileList; |
Głównym zadaniem tej procedury jest przeskanowanie archiwum i odnalezienie nazw oraz rozmiarów plików przechowywanych w archiwum. Ponieważ układ w naszym arch. jest sekwencyjny wystarczy abyśmy pobrali nazwę i rozmiar pliku na początku którego obecnie znajduje się nasz wewnętrzny stream, zapisujemy te dane, a następnie przeskakujemy o wielkość właśnie zbadanego pliku i trafiamy na początek następnego. Czynność tą powtarzamy aż dojdziemy do końca.
1 2 3 |
procedure AddFile(const name:string; const ExtractName:boolean = true);overload; procedure AddFile(const name:string; const stream:TStream);overload; |
Dzięki tej procce dodajemy nowe dane do naszego archiwum, jak widać dane mogą być pobierane z dowolnego streama (lub pliku), który zwróci nam swój rozmiar. Metoda na początku przeskakuje na koniec naszego archiwum, a później dopisuje do niego przekazane dane. Zanim jednak to zrobi sprawdza czy w naszym archiwum nie ma już pliku o podanej nazwie. W tej implementacji możliwe jest przekazanie całej ścieżki jako nazwy pliku. Nazwa jest Case sensitive !
1 |
procedure DeleteFile(const name:string; const imediate:boolean); |
Ponieważ jak wiemy usuwanie pliku jest czasochłonne ta metoda ma dodatkowy parametr imediate, który mówi czy usunięcie ma zostać wykonane zaraz po wywołaniu tej metody. Po co takie coś ? Ano jeśli ustawimy imediate na false, każde wywołanie tej procedury zapisze tylko nazwę pliku, który ma zostać usunięty. Na sam koniec, gdy już wybierzemy wszystkie pliki do skasowania wywołujemy ExecutePendingDeletion i całe kasowanie następuje dużo szybciej (w jednym przebiegu).
1 |
procedure ExecutePendingDeletion; |
Funkcja dokonuje właściwego kasowania z archiwum (polecam przyjrzeć się metodzie DeleteFile od środka). Idea jest bardzo prosta:
1. Tworzymy tymczasowy stream, do którego będziemy kopiowali dane.
2. Ustawiamy się na początku naszego archiwum
3. Pobieramy nazwę pliku z archiwum, jeśli ta nazwa jest na liście plików do skasowania przeskakujemy do punktu 5
4. Kopiujemy plik (nazwa + dane) do tymczasowego streama
5. Przechodzimy do kolejnego pliku w naszym archiwum, i wykonujemy punkt 3. Całość powtarzamy tak długo aż skończą się dane w archiwum.
6. Zamykamy tymczasowy stream, zamykamy nasze archiwum.
7. Kasujemy nasze archiwum, dokonujemy rename tymczasowego staremu (pliku) do nazwy jaką miało nasze stare archiwum i ponownie je otwieramy
1 |
function GetNextFileName:string; |
Funkcja zapamiętuje aktualna pozycje w streamie, następnie pobiera nagłówek pliku na początku którego ustawiony jest stream po czym powraca do pozycji zapamiętanej na początku. Jako rezultat zwraca pobraną nazwę pliku.
1 |
procedure SkipNextFile; |
Funkcja pobiera rozmiar pliku, na początku którego ustawiony jest stream po czym przeskakuje o tą wartość dalej, w rezultacie trafia na początek kolejnego pliku.
1 |
function GetNextFile(out FileSize:integer; const skipHeader:boolean=true):TStream; |
Funkcja zwraca pointer do streama z którego można pobrać plik na początku którego znajduje się stream. Jeśli skipHeader jest ustawiony na true, zwrócony stream będzie pokazywał na początek danych pliku. Jeśli zaś skipHeader = false stream będzie pokazywał na nagłówek pliku. W zmiennej FileSize zostanie zwrócona wielkość pliku. UWAGA: przeczytanie mniejszej lub większej ilości danych ze zwróconego streama niż FileSize powoduje, że nasze wewnętrzny stream jest gdzieś poza nagłówkami plików. Aby móc ponownie z niego korzystać należy wywołać procedure FindFileNamed, procedury które mają w nazwie NextFile nie będą poprawnie działać !
1 |
function FindFileNamed(const name: string; out FileSize:integer; const skipHeader:boolean=true):TStream; |
Działanie jest identyczne jak w GetNextFile, jedyna różnica polega na tym, że zwrócony stream będzie ustawiony na początku pliku o zadanej nazwie.
1 |
function GetNextFileSize:integer; |
Zasada działania identyczna jak w GetNextFileName, jedyna różnica polega na tym, że zwracane są inne dane z nagłówka.
1 |
function DataAvail:boolean; |
Funkcja zwraca true jeśli nie jesteśmy na końcu archiwum. Aby to sprawdzić wystarczy porównać czy pozycja w naszym wewnętrznym streamie jest mniejsza od wielkości pliku.
1 |
procedure ReorderFiles(const OrderedNames:TStrings); |
Procedura zmienia kolejność plików w archiwum. Zasada jest zbliżona do kasowania pliku, czyli tworzymy tymczasowy stream, do którego kopiowane są kolejno dane z naszego archiwum. Różnica polega na tym, że kolejne dane które będą skopiowane są wyszukiwane metodą FindFileNamed na podstawie zmiennej OrderedNames.
Ok. To tyle, trochę zwięźle i może lakonicznie, ale kod jest naprawdę prosty, proponuje poeksperymentować i zobaczyć jak to wygląda w praktyce. Wszelakie pytania mile widziane.
Autor: Toster
Do pobrania pełnej ścieżki dostępu służy funkcja ParamStr(0)
jednak czasem zachodzi potrzeba „rozbicia” jej ma poszczególne elementy
służą do tego następujące funkcje konwertujące:
* ExtractFileDir – pytanie o pełną ścieżkę katalogu bez nazwy pliku,
* ExtractFileDrive – pytanie o napęd dyskowy,
* ExtractFileExt – pytanie o rozszerzenie pliku,
* ExtractFileName – pytanie o nazwę pliku(z rozszerzeniem),
* ExtractFilePath – pytanie o pełną ścieżkę katalogu bez nazwy pliku,
ExtractFileDir od ExtractFilePath różni się tym że w tym pierwszym nie ma ukośnika na końcu
(np.: ExtractFileDir poda
„E:\gra2”
a ExtractFilePath poda
„E:\gra2\”
Autor: Sazian
Zapis i odczyt danych z pliku przy pomocy poleceń ObjectPascal
Zapis danych do pliku :
AssignFile – przypisanie zmiennej pliku
Rewrite – otwarcie pliku, jeśli plik nie istnieje to zostanie utworzony. Jeśli natomiast istnieje to jego dawna zawartość zostanie utracona.
Reset – otwiera plik, plik musi istnieć na dysku. Podczas otwarcia zawartość pliku nie jest tracona
Append – otwiera plik tekstowy do dalszego dopisywania. Wskaźnik ustawiony jest na końcu pliku
Write – zapis tekstu
WriteLn – zapis tekstu w nowej linii
CloseFile – zamknięcie pliku
TextFile – jeden z formatów pliku. Można również tworzyć pliki w innych formatach np. file of Char, File of Byte, File of Rect (dowolny rekord),..
Oto przykład :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
procedure TForm1.btnWriteClick(Sender: TObject); var F: TextFile; begin AssignFile(F, 'C:\TestData.txt'); Rewrite(F); WriteLn(F, Edit1.Text); WriteLn(F, Edit2.Text); CloseFile(F); end; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
procedure TForm1.btnWriteClick(Sender: TObject); var F: TextFile; S: String; begin AssignFile(F, 'C:\TestData.txt'); Rewrite(F); S:= '100 202'; // S:= Edit1.Text+' '+Edit2.Text; WriteLn(F, S); CloseFile(F); end; |
Odczyt danych z pliku :
Podobnie jak przy zapisie korzystamy z funkcji „pascalowych”. W skrócie :
FileExist – sprawdza czy plik o podanej nazwie istnieje
ReadLn – odczytuje linię tekstu z pliku, zapisuje ją w zmiennej String oraz przenosi wskaźnik do następnej lini.
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 26 27 28 29 30 31 32 33 |
procedure TForm1.btnReadClick(Sender: TObject); var F: TextFile; S: string; begin if FileExists('C:\TestData.txt') then begin AssignFile(F, 'C:\TestData.txt'); Reset(F); ReadLn(F, S); Edit1.Text := S; ReadLn(F, S); Edit2.Text := S; CloseFile(F); end else ShowMessage('Plik C:TestData.txt nie istnieje'); end; |
Autor: Nakiel
Pliki INI to nic innego jak pliki zawierające konfigurację jakiegoś programu. Coraz częściej te pliki zastępuje się korzystaniem z rejestru, co jest bardziej wygodne.
1.Przykładowa struktura naszego pliku (np. setup.ini):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
[Ustawienia] Tytul=Przykladowy Program X=100 Y=200 Szerokosc=400 Wysokosc=350 [Ostatnio otwierane] Plik1=C:a.txt Plik2=C:b.txt Plik3=C:c.txt |
Umieściliśmy w naszym pliku informacje o tytule programu, jego pozycji, szerokości, wysokości oraz ścieżki do trzech ostatnio otwieranych plików.
2.Tworzenie i zapis do plików
Na początku do deklaracji uses musimy dodać IniFiles, następnie plik konfiguracyjny tworzymy za pomocą polecenia Create np :
1 2 3 4 5 6 7 8 9 |
var ini: TInIFile; begin InI := TIniFile.Create(ExtractFilePath(ParamStr(0))+'setup.ini'); InI.Free; //czyści pamięć end; |
Zmienna ParamStr(0) zawiera ścieżka wraz z nazwą naszego programu. Poprzez polecenie ExtractFilePath wyciągniemy nazwę katalogu w którym znajduje się program. Dzięki temu plik setup.ini zostanie utworzony w tym katalogu gdzie znajduje się program.
Tworzenie nowych elementów:
Tekst :
1 |
InI.WriteString('Sekcja','Typ','Wartosc'); |
Liczba całkowita :
1 |
InI.WriteInteger('Sekcja','Typ',0); |
Włączony / Wyłączony :
1 |
InI.WriteBool('Sekcja','Typ',True); |
Data :
1 |
InI.WriteDate('Sekcja','Typ',TDate(Date)); |
Data i godzina :
1 |
InI.WriteDateTime('Sekcja','Typ',TDateTime(Time)); |
Godzina :
1 |
InI.WriteTime('Sekcja','Typ',TTime(Time)); |
Liczba rzeczywista :
1 |
InI.WriteFloat('Sekcja','Typ',4.23); |
Wartość binarna :
1 |
InI.WriteBinaryStream('Sekcja','Typ',Stream); |
Jeśli zapiszemy w/w polecenie (String) powinniśmy otrzymać :
1 2 3 |
[Sekcja] Typ=Wartosc |
3.Odczyt zmiennych z pliku
Do odczytu wartości używamy tych samych poleceń co do zapisy. Zastępujemy jedynie słowo Write(zapisz) słowem Read(odczytaj). Oto przykład odczytu wartości :
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 26 27 28 |
procedure TForm1.FormShow(Sender: TObject); var InI : TIniFile; begin InI := TIniFile.Create(ExtractFilePath(ParamStr(0))+'setup.ini'); try Form1.Caption := InI.ReadString('Ustawienia','Tytul',''); Form1.Left := InI.ReadInteger('Ustawienia','X',0); Form1.Top := InI.ReadInteger('Ustawienia','Y',0); Form1.Width := InI.ReadInteger('Ustawienia','Szerokosc',0); Form1.Height := InI.ReadInteger('Ustawienia','Wysokosc',0); finally InI.Free; end; end; |
4.Usuwanie zmiennych z pliku
Aby usunąć całą grupę np. Ustawienia musimy użyć polecenia
1 |
InI.EraseSection('Ustawienia'); |
zaś, jeśli chcemy usunąć tylko daną zmienną posłużymy się
1 |
InI.DeleteKey('Ustawienia','Tytul'); |
Przydatne może się okazać polecenie, które sprawdza czy dana grupa istnieje
1 |
if InI.SectionExists('Ustawienia') then ... |
5.Odczyt całych grup oraz ich wartości
Mamy możliwość zapisania np. do listy TListBox nazw wszystkich grup, zmiennych danej grupy, wartości zmiennych danej grupy. W tym celu posłużymy się poleceniami: Odczyt nazw grup :
1 |
InI.ReadSections(ListBox1.Items); |
Odczyt nazw zmiennych danej grupy :
1 |
InI.ReadSection('Ustawienia',ListBox1.Items); |
Odczyt wartości zmiennych danej grupy :
1 |
InI.ReadSectionValues('Ustawienia',ListBox1.Items); |
W ten sposób dotarliśmy do końca tej lekcji.
Posłuż się tym kodem:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
procedure WriteNodeData(const f:TFileStream; node:TTreeNode); var temp,t: integer; st: array[0..255] of char; begin //zapis nazwy temp := Length(node.Text); f.Write(temp, sizeof(integer)); for t := 0 to temp-1 do st[t] := node.text[t+1]; f.Write(st, temp); //zapis dzieci //ile dzieci temp := node.Count; f.Write(temp, sizeof(integer)); for t := 0 to temp-1 do WriteNodeData(f, node.Item[t]); end; procedure ReadNodeData(const f:TFileStream; node:TTreeNode); var temp,t: integer; st: array[0..255] of char; s: string; nod: TTreeNode; begin //odczyt nazwy f.Read( temp, sizeof(integer)); f.read(st, temp); s := ''; for t := 0 to temp-1 do s := s + st[t]; nod := form1.TreeView1.Items.AddChild(node, s); //ile dzieci f.Read( temp, sizeof(integer)); //zapis dzieci for t := 0 to temp-1 do ReadNodeData(f, nod); end; procedure TForm1.SaveData1Click(Sender: TObject); var f: TFileStream; t,y: integer; begin f := TFileStream.Create('tree.dat',fmCreate); t :=TreeView1.Items.Count; y := 0; for t := 0 to TreeView1.Items.Count -1 do if TreeView1.items[t].Level =0 then inc(y); f.Write(y,sizeof(integer)); for t := 0 to TreeView1.Items.Count -1 do if TreeView1.items[t].Level =0 then WriteNodeData(f, TreeView1.items[t]); f.free; end; procedure TForm1.LoadData2Click(Sender: TObject); var f: TFileStream; t,y: integer; begin TreeView1.Items.Clear; f := TFileStream.Create('tree.dat',fmOpenRead); f.read(y, sizeof(integer)); for t := 0 to y-1 do ReadNodeData(f, nil); f.free; end; |
Autor: Toster
Należy skorzystać z funkcji ExtractFilePath, która zwraca ściężkę do podanego w parametrze pliku. Jako argument wysyłamy nazwę exeka, którą odczytujemy z Application.ExeName:
1 2 3 4 |
var sciezkaDoAplikacji : String ; begin sciezkaDoAplikacji := ExtractFilePath(Application.ExeName) ; |
Autor: Iskar
Większość edytorów tekstowych posiada możliwość otwarcia pliku klikając na jego ikonę podczas przeglądania zawartości dysku. Aby również nasz program to potrafił wystarczy dodać krótki kod:
W OnShow Formy wpisz :
1 2 3 |
If ParamStr(1) <> '' then Memo1.Lines.LoadFromFile(ParamStr(1)); |
Na początku utworzymy odpowiednią funkcję, która będzie zwracać obiekt klasy TDateTime, a nastepnie przy pomocy FormatDateTime wyświetlimy datę na ekranie. Oto kod:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
function GetFileModifyDate(FileName: string): TDateTime; var h: THandle; Struct: TOFSTRUCT; lastwrite: Integer; t: TDateTime; begin h := OpenFile(PChar(FileName), Struct, OF_SHARE_DENY_NONE); try if h <> HFILE_ERROR then begin lastwrite := FileGetDate(h); Result := FileDateToDateTime(lastwrite); end; finally CloseHandle(h); end; end; procedure TForm1.Button1Click(Sender: TObject); begin if Opendialog1.Execute then label1.Caption := FormatDateTime('dddd, d. mmmm yyyy hh:mm:ss', GetFileModifyDate(Opendialog1.FileName)); end; |
Autor: Nakiel
Aby pobrać informacje na temat wykonawcy, tytułu, albumu, roku wydania oraz gatunku utworu z pliku MP3 to musimy odczytać jego ostatnie sektory. Ze względu na rozbudowaną strukturę tagów proponuję utworzyć osobny plik, w którym będzie znajdować się funkcją pobierająca dane …
Oto jego kod źródłowy :
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
unit ID3; interface {$A+} { Honor packed } {$Z1} { Byte storage for small enumerated types } type //wykaz gatunków ID3Genre = ( id3gBlues, id3gClassicRock, id3gCountry, id3gDance, id3gDisco,id3gFunk, id3gGrunge, id3gHipHop, id3gJazz, id3gMetal, id3gNewAge, id3gOldies, id3gOther, id3gPop, id3gRNB, id3gRap, id3gReggae,id3gRock, id3gTechno, id3gIndustrial, id3gAlternative, id3gSka, id3gDeathMetal, id3gPranks, id3gSoundtrack, id3gEuroTechno,id3gAmbient, id3gTripHop, id3gVocal, id3gJazzFunk, id3gFusion,id3gTrance, id3gClassical, id3gInstrumental, id3gAcid, id3gHouse, id3gGame, id3gSoundClip, id3gGospel, id3gNoise, id3gAlternRock, id3gBass, id3gSoul, id3gPunk, id3gSpace, id3gMeditative, id3gInstrumentalPop, id3gInstrumentalRock, id3gEthnic, id3gGothic,id3gDarkwave, id3gTechnoIndustrial, id3gElectronic, id3gPopFolk, id3gEurodance, id3gDream, id3gSouthernRock, id3gComedy, id3gCult, id3gGangsta, id3gTop40, id3gChristianRap, id3gPopFunk, id3gJungle, id3gNativeAmerican, id3gCabaret, id3gNewWave, id3gPsychadelic, id3gRave, id3gShowtunes, id3gTrailer, id3gLoFi, id3gTribal, id3gAcidPunk, id3gAcidJazz, id3gPolka, id3gRetro, id3gMusical, id3gRockNRoll, id3gHardRock, id3gFolk, id3gFolkRock, id3gNationalFolk, id3gSwing, id3gFastFusion, id3gBebob, id3gLatin, id3gRevival, id3gCeltic, id3gBluegrass, id3gAvantgarde, id3gGothicRock, id3gProgressiveRock, id3gPsychedelicRock, id3gSymphonicRock, id3gSlowRock, id3gBigBand, id3gChorus, id3gEasyListening, id3gAcoustic, id3gHumour, id3gSpeech, id3gChanson, id3gOpera, id3gChamberMusic, id3gSonata, id3gSymphony, id3gBootyBass, id3gPrimus, id3gPornGroove, id3gSatire, id3gSlowJam, id3gClub, id3gTango, id3gSamba, id3gFolklore, id3gBallad,id3gPowerBallad, id3gRhythmicSoul, id3gFreestyle, id3gDuet, id3gPunkRock, id3gDrumSolo, id3gAcapella, id3gEuroHouse, id3gDanceHall ); ID3Struct = packed record Magic: array [0..2 ] of Char; //identyfikator Title: array [0..29] of Char; //tytuł Artist: array [0..29] of Char; //artysta Album: array [0..29] of Char; //album Year: array [0..3 ] of Char; //rok Comment: array [0..29] of Char; //komentarz Genre: ID3Genre; // gatunek end; const ID3Magic = 'TAG'; ID3OffsetFromEnd = 128; //odległość od końca pliku zarezerwowana dla tagów ID3UnknowGenre = ID3Genre(255); // nieznany gatunek //tablica gatunków ID3GenreName: array [ID3Genre] of PChar = ( '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', 'AlternRock', 'Bass', 'Soul', '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 American', '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', 'Rhythmic Soul', 'Freestyle', 'Duet', 'Punk Rock', 'Drum Solo', 'Acapella', 'Euro-House', 'Dance Hall' ); function GetMP3Infos(FN:String): id3struct; // FN - nazwa pliku implementation function GetMP3Infos(FN:String): id3struct; var F: File of Byte; Tag: ID3Struct; HasTag: Boolean; GenreName: String; NewFN: String; const Tab = #9; begin AssignFile(F, fn); try Reset(F); try Seek(F, FileSize(F) - ID3OffsetFromEnd); BlockRead(F, Tag, SizeOf(Tag)); HasTag := Tag.Magic = ID3Magic; if not HasTag then begin FillChar(Tag, Sizeof(Tag), ' '); Tag.Magic := ID3Magic; Tag.Genre := ID3UnknowGenre; end; CloseFile(f); Result:=Tag; except end; except end; end; end. |