Get size and dates of a file with one call

Just starting out? Need help? Post your questions and find answers here.
Lebostein
Addict
Addict
Posts: 826
Joined: Fri Jun 11, 2004 7:07 am

Get size and dates of a file with one call

Post 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?
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Get size and dates of a file with one call

Post 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))
Windows (x64)
Raspberry Pi OS (Arm64)
Lebostein
Addict
Addict
Posts: 826
Joined: Fri Jun 11, 2004 7:07 am

Re: Get size and dates of a file with one call

Post by Lebostein »

Yeah! Thanks! Just what I expected! This speeds up my file scaning tool by a factor of 4 !!! :P
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! */
     };
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Get size and dates of a file with one call

Post by Shardik »

For the structure definiton of stat64 yoy may take a look into this posting of Airr.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Get size and dates of a file with one call

Post 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_.
Windows (x64)
Raspberry Pi OS (Arm64)
Fred
Administrator
Administrator
Posts: 18153
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: Get size and dates of a file with one call

Post 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.
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Get size and dates of a file with one call

Post 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.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Get size and dates of a file with one call

Post 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 :shock: :idea:
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.
Windows (x64)
Raspberry Pi OS (Arm64)
Lebostein
Addict
Addict
Posts: 826
Joined: Fri Jun 11, 2004 7:07 am

Re: Get size and dates of a file with one call

Post 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!
User avatar
skywalk
Addict
Addict
Posts: 4210
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Get size and dates of a file with one call

Post 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().
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Get size and dates of a file with one call

Post 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.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
blueb
Addict
Addict
Posts: 1111
Joined: Sat Apr 26, 2003 2:15 pm
Location: Cuernavaca, Mexico

Re: Get size and dates of a file with one call

Post 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
- It was too lonely at the top.

System : PB 6.21(x64) and Win 11 Pro (x64)
Hardware: AMD Ryzen 9 5900X w/64 gigs Ram, AMD RX 6950 XT Graphics w/16gigs Mem
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Get size and dates of a file with one call

Post 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
Lebostein
Addict
Addict
Posts: 826
Joined: Fri Jun 11, 2004 7:07 am

Re: Get size and dates of a file with one call

Post by Lebostein »

It seemsbetween the stat64 and the PureBasic functions there is a difference of two hours. Is that the GMT+X offset?
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Get size and dates of a file with one call

Post 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.
Windows (x64)
Raspberry Pi OS (Arm64)
Post Reply