Page 1 of 2
Get size and dates of a file with one call
Posted: Fri Jul 20, 2018 5:36 am
by Lebostein
If you need the size and the dates of a file, you have to do 4 file accesses with PureBasic:
Code: Select all
FileSize(path$)
GetFileDate(path$, #PB_Date_Created)
GetFileDate(path$, #PB_Date_Accessed)
GetFileDate(path$, #PB_Date_Modified)
That is very slow.
For example in Python you need only one function for that and I suppose there is only one file access to read out all informations:
https://www.tutorialspoint.com/python/os_stat.htm
Are there Windows and Mac OS API functions that can do the same?
Re: Get size and dates of a file with one call
Posted: Fri Jul 20, 2018 9:06 am
by wilbert
Lebostein wrote:Are there Windows and Mac OS API functions that can do the same?
The stat (or stat64) function could be used but the output is different for different OS and 32/64 bit.
For example on PB Mac 64 bit, this seems to work (UTC times)
Code: Select all
ImportC ""
stat64(path.p-utf8, *buf)
EndImport
Global Dim buf.q(17); 144 bytes
stat64("Test2.pb", @buf())
Debug "Last access : " + FormatDate("%yyyy/%mm/%dd %hh:%ii:%ss", buf(4))
Debug "Last data modification : " + FormatDate("%yyyy/%mm/%dd %hh:%ii:%ss", buf(6))
Debug "Last status change : " + FormatDate("%yyyy/%mm/%dd %hh:%ii:%ss", buf(8))
Debug "File creation : " + FormatDate("%yyyy/%mm/%dd %hh:%ii:%ss", buf(10))
Debug "File size : " + Str(buf(12))
Re: Get size and dates of a file with one call
Posted: Fri Jul 20, 2018 1:43 pm
by Lebostein
Yeah! Thanks! Just what I expected!
This speeds up my file scaning tool by a factor of 4 !!!
It is possible to replace that buf()-array with a real structure?
I found that, but I am not sure which size 32/64 the single entries have:
Code: Select all
struct stat { /* when _DARWIN_FEATURE_64_BIT_INODE is defined */
dev_t st_dev; /* ID of device containing file */
mode_t st_mode; /* Mode of file */
nlink_t st_nlink; /* Number of hard links */
ino_t st_ino; /* File serial number 64 bits */
uid_t st_uid; /* User ID of the file */
gid_t st_gid; /* Group ID of the file */
dev_t st_rdev; /* Device ID */
struct timespec st_atimespec; /* time of last access */
struct timespec st_mtimespec; /* time of last data modification */
struct timespec st_ctimespec; /* time of last status change */
struct timespec st_birthtimespec; /* time of file creation(birth) added */
off_t st_size; /* file size, in bytes */
blkcnt_t st_blocks; /* blocks allocated for file */
blksize_t st_blksize; /* optimal blocksize for I/O */
uint32_t st_flags; /* user defined flags for file */
uint32_t st_gen; /* file generation number */
int32_t st_lspare; /* RESERVED: DO NOT USE! */
int64_t st_qspare[2]; /* RESERVED: DO NOT USE! */
};
Re: Get size and dates of a file with one call
Posted: Fri Jul 20, 2018 2:57 pm
by Shardik
For the structure definiton of
stat64 yoy may take a look into
this posting of Airr.
Re: Get size and dates of a file with one call
Posted: Fri Jul 20, 2018 3:18 pm
by wilbert
Shardik wrote:For the structure definiton of
stat64 yoy may take a look into
this posting of Airr.
Confusing
Those field sizes are totally different from what XCode reports.
I get something like
Code: Select all
Structure timespec
tv_sec.i
tv_nsec.i
EndStructure
Structure stat64
st_dev.l
st_mode.w
st_nlink.w
st_ino.q
st_uid.l
st_gid.l
st_rdev.l
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
_padding_.l
CompilerEndIf
st_atimespec.timespec
st_mtimespec.timespec
st_ctimespec.timespec
st_birthtimespec.timespec
st_size.q
st_blocks.q
st_blksize.l
st_flags.l
st_gen.l
st_lspare.l
st_qspare.q[2]
EndStructure
ImportC ""
stat64(path.p-utf8, *buf)
EndImport
stat64("test.txt", @stat.stat64)
Debug "Last access : " + FormatDate("%yyyy/%mm/%dd %hh:%ii:%ss", stat\st_atimespec\tv_sec)
Debug "Last data modification : " + FormatDate("%yyyy/%mm/%dd %hh:%ii:%ss", stat\st_mtimespec\tv_sec)
Debug "Last status change : " + FormatDate("%yyyy/%mm/%dd %hh:%ii:%ss", stat\st_ctimespec\tv_sec)
Debug "File creation : " + FormatDate("%yyyy/%mm/%dd %hh:%ii:%ss", stat\st_birthtimespec\tv_sec)
Debug "File size : " + Str(stat\st_size)
I also had some trouble with the alignment between 32 and 64 bit PB on MacOS; that's why I added _padding_.
Re: Get size and dates of a file with one call
Posted: Fri Jul 20, 2018 3:45 pm
by Fred
I didn't tested it, but may be you can use ExamineDirectory() with your filename as pattern, and use the DirectoryEntryDate()/Size() function it should be faster as it's only one call.
Re: Get size and dates of a file with one call
Posted: Fri Jul 20, 2018 3:57 pm
by Shardik
wilbert wrote:I also had some trouble with the alignment between 32 and 64 bit PB on MacOS; that's why I added _padding_.
You also posted at the end of the thread with Airr's posting and wrote:
wilbert wrote:I know this is a very old thread but I verified the structure for both 32 and 64 bits.
Code: Select all
ImportC ""
stat64(path.p-ascii, *buf)
getpwuid(uid)
getgrgid(gid)
EndImport
Structure timespec
tv_sec.i
tv_nsec.i
EndStructure
Structure stat64
st_dev.l; /* ID of device containing file */
st_mode.w; /* Mode of file */
st_nlink.w; /* Number of hard links */
st_ino.q; /* File serial number */
st_uid.l; /* User ID of the file */
st_gid.l; /* Group ID of the file */
st_rdev.i; /* Device ID */
st_atimespec.timespec; /* time of last access */
st_mtimespec.timespec; /* time of last data modification */
st_ctimespec.timespec; /* time of last status change */
st_birthtimespec.timespec; /* time of file creation(birth) */
st_size.q; /* file size, in bytes */
st_blocks.q; /* blocks allocated for file */
st_blksize.l; /* optimal blocksize for I/O */
st_flags.l; /* user defined flags for file */
st_gen.l; /* file generation number */
st_lspare.l; /* RESERVED: DO NOT USE! */
st_qspare.q[2]; /* RESERVED: DO NOT USE! */
EndStructure
stat64("MyFile", @stats.stat64)
Debug "File size : " + Str(stats\st_size)
Debug "User name : " + PeekS(PeekI(getpwuid(stats\st_uid)), -1, #PB_Ascii)
Debug "Group name : " + PeekS(PeekI(getgrgid(stats\st_gid)), -1, #PB_Ascii)
Debug "Last access : " + FormatDate("%yyyy/%mm/%dd", stats\st_atimespec\tv_sec)
Did you find out the necessity for the alignment only recently?
Sorry for not directly linking to your last posting in that thread.
Re: Get size and dates of a file with one call
Posted: Fri Jul 20, 2018 4:22 pm
by wilbert
Shardik wrote:Did you find out the necessity for the alignment only recently?
Sorry for not directly linking to your last posting in that thread.
I should have read that thread more carefully
I overlooked my own post and didn't even remember I had looked at stat64 before.
Anyway, I chose a different way in that post to solve the alignment.
Even while st_rdev reports 4 bytes in XCode I typed it as .i so it would become 8 bytes on x64.
When it comes to the alignment the effect is the same as my solution in this thread but the solution in the other thread looks cleaner I guess.
Re: Get size and dates of a file with one call
Posted: Fri Jul 20, 2018 5:30 pm
by Lebostein
Fred wrote:I didn't tested it, but may be you can use ExamineDirectory() with your filename as pattern, and use the DirectoryEntryDate()/Size() function it should be faster as it's only one call.
Yes! Very good hint. It seems that is the thing I need. I had not noticed these commands yet...
Thanks also @Wilbert and @Shardik for your informations!
Re: Get size and dates of a file with one call
Posted: Fri Jul 20, 2018 6:57 pm
by skywalk
Always good to speed things up, but the Windows __stat64 structure does not match what is listed here.
I get filesize from \st_rdev. Just pause the code and look at the structure with the memoryviewer.
Just use the PB functions:
iDir = ExamineDirectory(#PB_Any, Path$, Pat$)
If iDir
While NextDirectoryEntry(iDir)
;...
FinishDirectory(iDir)
or Windows api:
WIN32_FIND_DATA struct while stepping through a directory/subdirs with FindFirstFile()/FindNextFile().
Re: Get size and dates of a file with one call
Posted: Fri Jul 20, 2018 7:32 pm
by wilbert
skywalk wrote:Always good to speed things up, but the Windows __stat64 structure does not match what is listed here.
That's right. For Windows 64 bit it looks like this as far as I can tell
Code: Select all
Structure _stat64 Align #PB_Structure_AlignC
st_dev.l
st_ino.u
st_mode.u
st_nlink.w
st_uid.w
st_gid.w
st_rdev.l
st_size.q
st_atime.q
st_mtime.q
st_ctime.q
EndStructure
ImportC ""
_stat64(path.p-utf8, *buf)
EndImport
_stat64("test.txt", @stat._stat64)
Debug "Last access : " + FormatDate("%yyyy/%mm/%dd %hh:%ii:%ss", stat\st_atime)
Debug "Last data modification : " + FormatDate("%yyyy/%mm/%dd %hh:%ii:%ss", stat\st_mtime)
Debug "Last status change : " + FormatDate("%yyyy/%mm/%dd %hh:%ii:%ss", stat\st_ctime)
Debug "File size : " + Str(stat\st_size)
Windows also has an API function named
GetFileTime.
Re: Get size and dates of a file with one call
Posted: Sat Jul 21, 2018 4:49 pm
by blueb
Fred wrote:I didn't tested it, but may be you can use ExamineDirectory() with your filename as pattern, and use the DirectoryEntryDate()/Size() function it should be faster as it's only one call.
I don't know if this is what you mean't... but this works as well as I need. Thanks Fred.
My timer results on a dual Xeon E5-2670 was 179 msecs. using the Debugger (below).
Note: You can leave out the Hi Res timer, if you wish.
Code: Select all
;==================================================================
;
; Author: blueb
; Date: July 21, 2018
; Explain:
;
; Typical Usage: Test out Fred's theory.
;==================================================================
XIncludeFile "HighResTimer - Module.pb"
; search for StarBootics HighResTimer module. NOTE: file was modified by Demivec
; see: https://www.purebasic.fr/english/viewtopic.php?p=492584#p492584
HighResTimer::Initialize() ; <-- Mandatory to Initialize the timer before using it
HighResTimer::Start()
Directory$ = GetCurrentDirectory() ; Desired directory
FileName$ = "BobTest.pb" ; Use an existing file name for testing purposes.
If ExamineDirectory(0, Directory$, FileName$)
While NextDirectoryEntry(0)
If DirectoryEntryType(0) = #PB_DirectoryEntry_File
Type$ = "File Name: "
Size$ = "File Size: " + DirectoryEntrySize(0) +" bytes."
Created = DirectoryEntryDate(0, #PB_Date_Created)
Accessed = DirectoryEntryDate(0, #PB_Date_Accessed)
Modified= DirectoryEntryDate(0, #PB_Date_Modified)
EndIf
;See the results
Debug Type$ + DirectoryEntryName(0)
Debug Size$
Debug ""
Debug "Date Created: " + FormatDate("%mm/%dd/%yyyy... %hh:%ii:%ss", Created)
Debug "Last Accessed: " + FormatDate("%mm/%dd/%yyyy... %hh:%ii:%ss", Accessed)
Debug "Last Modified: " + FormatDate("%mm/%dd/%yyyy... %hh:%ii:%ss", Modified)
Wend
FinishDirectory(0)
EndIf
;Done
Debug "-----"
Debug Str(HighResTimer::Consult()) + " msecs"
HighResTimer::Stop()
;end
Re: Get size and dates of a file with one call
Posted: Sat Jul 21, 2018 10:50 pm
by infratec
As a usable procedure:
Code: Select all
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
CompilerEndIf
Structure FileInfoStructure
Size.q
Created.i
Accessed.i
Modified.i
EndStructure
Procedure.i GetFileInfo(FileName$, *FileInfo.FileInfoStructure)
Protected Result.i, Dir.i
Dir = ExamineDirectory(#PB_Any, GetPathPart(FileName$), GetFilePart(FileName$))
If Dir
If NextDirectoryEntry(Dir)
If DirectoryEntryType(Dir) = #PB_DirectoryEntry_File
*FileInfo\Size = DirectoryEntrySize(Dir)
*FileInfo\Created = DirectoryEntryDate(Dir, #PB_Date_Created)
*FileInfo\Accessed = DirectoryEntryDate(Dir, #PB_Date_Accessed)
*FileInfo\Modified = DirectoryEntryDate(Dir, #PB_Date_Modified)
Result = #True
EndIf
EndIf
FinishDirectory(Dir)
EndIf
ProcedureReturn Result
EndProcedure
CompilerIf #PB_Compiler_IsMainFile
Define FileInfo.FileInfoStructure
If GetFileInfo("c:\windows\regedit.exe", @FileInfo)
Debug "Size: " + FileInfo\Size
Debug "Date Created: " + FormatDate("%mm.%dd.%yyyy %hh:%ii:%ss", FileInfo\Created)
Debug "Last Accessed: " + FormatDate("%mm.%dd.%yyyy %hh:%ii:%ss", FileInfo\Accessed)
Debug "Last Modified: " + FormatDate("%mm.%dd.%yyyy %hh:%ii:%ss", FileInfo\Modified)
EndIf
CompilerEndIf
Bernd
Re: Get size and dates of a file with one call
Posted: Sun Jul 22, 2018 9:23 am
by Lebostein
It seemsbetween the stat64 and the PureBasic functions there is a difference of two hours. Is that the GMT+X offset?
Re: Get size and dates of a file with one call
Posted: Sun Jul 22, 2018 9:45 am
by wilbert
Lebostein wrote:It seemsbetween the stat64 and the PureBasic functions there is a difference of two hours. Is that the GMT+X offset?
Yes, stat64 returns time as UTC so it will return the same time value wherever you live.