Delphi FAQ

FAQ

13 komentarzy

Uwaga Terrmita jest w pełni uzasadniona. Ma to szczególne znaczenie, gdy chcemy w jakiś konkretny sposób wykorzystać wynik badania konkretnego pliku. Jeśli jednak chcemy jedynie dowiedzieć sie jaka jest suma wielkości zestawu plików, to czy zwrócona wartość będzie zerowa ponieważ plik nie istnieje lub będzie zerowy jego rozmiar, to dla sumy i tak nie ma to znaczenia. Aby jednak funkcja dawała jednoznaczne wyniki to należy zastosować poprawkę Terrmita. Niestety ta funkcja nie uwzględnia katalogów i plików ukrytych i systemowych czyli tych z różnymi ograniczeniami dostępu. Wynik badania np. katalogu WINDOWS daje złe wyniki. Najlepsze rozwiązanie dał Szczawik na forum ('rozmiar plików i katalogów'). Pierwszy algorytm działa wyśmienicie i nadaje się do większości zastosowań: oto on (reszta info na forum):
function GetDirSize(Path:TFileName):int64;
type Int64Record = record
case boolean of
TRUE: (Int:Int64);
FALSE: (Lo, Hi:DWORD);
end;
var Search:TSearchRec;
Handle:THandle;
Size:Int64Record;
begin
Path:=IncludeTrailingPathDelimiter(Path);
result:=0;
if (FindFirst(Path+'*', faAnyFile, Search) = 0) then
begin
repeat
if (Search.Name<'.') and (Search.Name<'..') then
begin
if (Search.Attr and faDirectory>0) then
result:=result+GetDirSize(Path+Search.Name)
else
begin
Handle:=CreateFile(PChar(Path+Search.Name), 0, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if (Handle<invalid_handle_value) then<br="then&lt;br" /> begin
Size.Lo:=GetFileSize(Handle, @Size.Hi);
result:=result+Size.Int;
CloseHandle(Handle);
end;
end;
end;
until (FindNext(Search)<0);
FindClose(Search);
end;
end;


W pomyśle Krzemina jest mały błąd. należy zamienić:
FS.Create(FileName,fmOpenRead or fmShareCompat);
na:
FS:= TFileStream.Create(FileName,fmOpenRead or fmShareCompat);
Reszta działa dobrze i nadaje sie do niektórych zastosowań.

Heh, wszystkie sposiby na pobranie rozmiaru pliku (FileSize, FindFirst itp...) mogą nieźle świrować przy wiekszych plikach.
Sam miałem tego typu problem i rozwiązałem go używając klasy TFileStream:

function GetFileSize(const FileName: string):Int64;
var
   FS:TFileStream;
begin
   if not FileExists(FileName) then
      Result:=0
   else
   begin
      FS.Create(FileName,fmOpenRead or fmShareCompat);
      Result:=FS.Size;
      FS.Free;
   end;
end;

Oczywiście powodem wykrzaczania pozostałych sposobów jest zakres, w jakim podają rozmiar pliku (Integer), co w przypadku TFileStream.Size
jest Int64...

Sposobem na ominiecie 'świrowania' przy zwracianiu rozmiaru pliku jest konwersja na typ nieoznaczony....

DWORD(...) (c/delphi)
(DWORD)... (tylko c)

... i problem znika. Zresztą tak sie powinno postepować z każdą funkcją/zmienną, która jest, a nie powinna być oznaczona.

Najlepiej to chyba tak:

function GetFileSize(const FileName: string):Int64;
var
ms : tmemorystream;
begin
if not FileExists(FileName) then
Result:=0
else
begin
ms := tmemorystream.Create;
ms.LoadFromFile(filename);
result:=ms.Size;
Freeandnil(ms);
end;
end;

Ładując to do Tfilestream plik nie może być używany, co uniemożliwia chodzby sprawdzenie rozmiaru własnego progrmau. Tmemorystream wczyta wszystko.

można i tak

function rozmiarpliku(Path:TFileName):int64;
type Int64Record = record
case boolean of
TRUE: (Int:Int64);
FALSE: (Lo, Hi:DWORD);
end;
var Search:TSearchRec;
Handle:THandle;
Size:Int64Record;
begin
result:=0;
Handle:=CreateFile(PChar(Path), 0, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if (Handle<invalid_handle_value) then<br="then&lt;br" /> begin
Size.Lo:=GetFileSize(Handle, @Size.Hi);
result:=Size.int;
CloseHandle(Handle);
end;
end;

Ja bym jeszcze w przykładzie Krzemina zmienił
if not FileExists(FileName) then
Result:=0
na
if not FileExists(FileName) then
Result:=-1
Wynik -1 wskazywałby wówczas na wystąpienie błędu. Bo przecież mogą być pliki o zormiarze 0. W ten sposób można dodatkowo odróżnić pliki istniejące, ale puste, od nieistniejących.

UnAdamBoduch: a ty pisać poprawnie :)

Marooned naucz się prograować lepeij :D

Owszem, tamat jest prosty, ale nie wszyscy sami potrafia napisac taka funkcje... i to glownie dla nich.

A tak przy okazji - nie zerznalem tego z pliku xyz, ani netu :-p

Dobrze wiedziec jak takie cosik samemu zaimplementowac...

jes też funkcja FileSize... wotek, nie mogłeś znaleźć trudniejszego tematu?

A nie lepiej FileOpen, Seek, FileClose?

Heh, pewnie to wziąłeś z przykładu do delphi (znajduje się w <delphi>Demos\Doc\Filmanex z pliku FmxUtils.pas... przynajmniej identycznie tam jest rozwiązane:D