Jobs!
Meetups by TopicMeetups by CityStart a MeetupWhat's Meetup
Also in: C/C++ · C# · Web Technology

Join Oslo Delphi Club!

We'll never share your email address without your permission. Already a Meetup member? Sign in.

Messages

Filstørrelse --- FileSize

Message Board › Filstørrelse --- FileSize

Christer Gustafsso...
user 3199174
Oslo, NO
5th Post

Var på trevlig pizzakväll igår. Jag provade min senaste Delphi-"kræsj" på några av de närvarande, men tyckte inte att deras svar verkade helt tillförlitliga. Jag provar det igen i ett större forum, då saken borde vara av allmänt intresse, nämligen att avläsa en fils storlek.

Påstående: Nedanstående funktion är en (den enda?) säker metod att avläsa filstorlek [bytes] i Windows på en godtycklig fil.

Är ni eniga?


function FileSizei64(fn : string): int64;
// Ref.: Lischner, p209 FileSize bullet 3 under "Errors"
const
OffsetZero : int64 = 0 ;
Origin : integer = 2 ;
var
UnitNumber : integer ; // Fortran 90/95 ...
begin
UnitNumber := sysutils.FileOpen(fn, fmOpenRead) ;
FileSizei64 := sysutils.FileSeek(UnitNumber,OffsetZero, Origin);
FileClose(UnitNumber)
end{FileSizei64};

Hallvard Vassbotn
hvassbotn
Oslo, NO
47th Post

I nyere Delphi versjoner kan du også bruke FindFirst for å få tak i filstørrelser for filer over 2GB:

Fra SysUtils:

TSearchRec = record
Time: Integer;
Size: Int64;
...

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

Kode-eksempel:
if FindFirst(Path, Attr, SearchRec) = 0 then
Result := SearchRec.Size
else
Result := -1; // File does not exist
FindClose(SearchRec);

Alternativt dersom du har en file handle, kan du bruke Windows.GetFileSize direkte:

function GetFileSize(hFile: THandle; lpFileSizeHigh: Pointer): DWORD; stdcall;

Men du må kombinere resultatet med verdien som pekes på av lpFileSizeHigh.

Siste alternativ er å åpne filen med TFileStream og lese Size property'en:

TStream = class(TObject)
...
property Size: Int64 read GetSize write SetSize64;
...
TFileStream = class(THandleStream)

Jon Lennart Aasend...
user 6619959
Tønsberg, NO
3rd Post

Denne burde gjøre susen:

Function FileSize64(Const Filename:AnsiString):Int64;
var
FRec: TSearchRec;
Begin
if FindFirst(FileName, faAnyFile, FRec)=0 then
Begin
try
Result := Int64(FRec.FindData.nFileSizeHigh) shl Int64(32)
+ Int64(FRec.FindData.nFileSizeLow);
finally
FindClose(FRec);
end;
end else
result:=0;
end;

Edited by Jon Lennart Aasenden on Mar 8, 2008 at 1:41 AM

Christer Gustafsso...
user 3199174
Oslo, NO
6th Post

Hjärtligt tack för flera trevliga svar i vilka många alternativ givits. Vilket skall jag nu välja?

Det sista är vekligt pedagogiskt och ger klar insyn i taldefinitionen (visste icke att man kan ange hur många bitar man vill skifta). Men den bryter mot min uppfattninga av högnivåspråk: jag arbetar inte med en assembler. Vidare behöver jag inte TSearchRec.

Min kod använder inte Streams, och intellektuell lättja (ack ja) , samt TSearchRec, gör att jag förkastar denna.

windows.GetFileSize verkar vara det upplagda valet: filens storlek "ägs" ju av operativsystemet och vad vore mer naturligt än att hämta det härifrån? Men parametrarna kräver samma hantering på assemblernivå, vilken förkastats ovan. Vidare förefaller denna funktion att vara ett museumföremål: Microsoft har en modern GetFileSizeEX med ett mycket "rent" anrop, men denna finns ej i Delphi (varken i 6 eller 2006 vilka jag har i maskinen min).


Därför behåller jag min FileSeek-baserade sak vilken exekverar blott litet långsammare än den windowsbaserade metoden. Den av Vassbotten först föreslagna är litet långsammare. (Tiderna var 170, 160 och 150 mikrosekunder respektive). Men dessa tider är ju försumbara med den tid det tar att leta upp filen: 18 millisekunder.

Resultatet blir att jag använder FileSeek med sitt högnivåinterface tills dess att GetFileSizeEX bilr tillgänglig i Delphi.

Ch

P.S. När jag väl fått ordning på filens storlek (4.8GB), så kraschade mitt program ändå när jag skulle kontrollera att jag fått rätt filstorlek. Filen är skriven i FØRTRAN och den är blockad. med blockstorlek FTNBlock:integer Jag räknar ut antalet block NB:longint sedan jag läst av filens storlek siz:int64. Sedan gick det alltså illa i jämförelsen

if siz<>NB*FTNBlock then Error;

Lösningen blev här att göra en typomvandling NB*int64(FTNBlock)

På det gamla ASEA i Västerås var dataavdelningens inställning att "användarna stör driften" ... jag är enig.

Jon Lennart Aasend...
user 6619959
Tønsberg, NO
4th Post

Men den bryter mot min uppfattninga av högnivåspråk: jag arbetar inte med en assembler

Dette var en underlig resonering, men alltid gøy å se hvordan andre mennesker kommer frem til sine løsninger :)

Personlig mener jeg at Delphi aldri har vært et høynivåspråk, og det finnes helt ærlig ikke en linje assembler i koden over. Det er windows som splitter øvre og nedre del av en INT64 her, ikke jeg -- og da må man bruke en bit-shift for å sette de sammen igjen.

samt TSearchRec, gör att jag förkastar denna

TSearchRec er definert i sysutils, så denne følger med i programmet enten du vil eller ej. Så det er liten hensikt å forkaste den.

Et høynivåspråk er (i mine øyne) Visual Basic, Realbasic eller (gud forby) Java. Disse trenger en enorm arkitektur for å kjøre (de kan ikke patches og kjøres fra DOS for eksempel, slik Delphi kan). Delphi er i større grad et lavnivåspråk, men med et klasse bibliotek (VCL) som gir brukerne en viss høynivå følelse. En god ballanse vil jeg si.
I et høynivå språk ville du knappest fått lov til å utføre en så åpen bit-shift, for ikke å snakke om assembler.

Men, det er jo dette som er det fine med Delphi! At alle mennesker kan bruke Delphi på sin måte og med sine teknikker.

Edited by Jon Lennart Aasenden on Mar 9, 2008 at 2:23 PM

Hallvard Vassbotn
hvassbotn
Oslo, NO
48th Post

Enda et alternativ:

http://msdn2.microsof...

function GetFileSizeEx(hFile: THandle; var FileSize: Int64): BOOL; stdcall; external 'kernel32.dll';

Christer Gustafsso...
user 3199174
Oslo, NO
7th Post

Tack Hallvard! Nu fick jag precis det jag behøvde med GetFileSizeEx.

Ur något hemmasnickrat bibliotek använder jag alltid en Exist(fn) och den är nu "overloaded" till

FUNCTION Exist(fn:FILENAME; var siz :int64 ):BOOLEAN;
{function GetFileSizeEx(hFile: THandle; var FileSize: Int64): BOOL; stdcall; external 'kernel32.dll';}
var
UnitNumber : integer ; // Should have been windows.THandle
begin
UnitNumber := sysutils.FileOpen(fn, fmOpenRead) ;
Exist:=false ;
if UnitNumber>0 then begin
Exist:=GetFileSizeEX(UnitNumber,siz); FileClose(UnitNumber)
end {case}
END; { Exist GetFileSizeEX}


Notera att THandle är cardinal i Delphi men FileOpen sänder en -1 om filen ej existerar, vilket naturligtvis ledde till att jag fick "range check error".

Powered by mvnForum