LuaFileSystem compatible Attributes using LuaCOM and fhFileUtils

This derives LuaFileSystem compatible attributes using LuaCOM and fhFileUtils library functions.

The lfs.attributes(filepath) function returns a table of attribute values, but only if the filepath is ANSI compatible, so is not suitable for all files.

The LuaCOM and fhFileUtils library functions support any filepath containing any Unicode characters, but omit some important attribute values which these snippets supply.

For example, the file created, modified & accessed date-times are text strings in the local format that are almost impossible to sort or compare rationally. Whereas, the LuaFileSystem date-times use UNIX epoch integer seconds since 1 Jan 1970 that easily sort and compare.

The table entry for each filepath has attribute values for mode, size, change, modification & access similar to the LuaFileSystem values.

The mode values are "directory" or "file" that easily differentiate folders and files. The FolderExists(filepath) and FileExists(filepath) functions can also be used.

The byte size values are more accurate for folders than the LuaFileSystem.

The change, modification & access times may differ from the LuaFileSystem by 1 hour (3600 seconds) due to Daylight Saving Time discrepancies.

The luacom.DateFormat options are defined in the LuaCOM User Manual V1.3 section 3.4.6 DATE type and the lua.config usage in section 3.3.5 Exception Handling.

Requires: luacom or fhFileUtils

Code for File Attributes

This works for ƒh V5, V6, and V7, and provides the attributes of one file or folder.

require("luacom")

function FileAttributes( strPath )

  local function intTime( tblT )	-- Convert Y/M/D H:M:S to UNIX epoch seconds past 1/1/1970
    return os.time({ year=tblT.Year or 1970; month=tblT.Month or 1; day=tblT.Day or 1; hour=tblT.Hour or 0; min=tblT.Minute or 0; sec=tblT.Second or 0; })
  end

  local tblAttr = {}
  local fso = luacom.CreateObject("Scripting.FileSystemObject")
  local fsoObject
  local oldAbort_on_Error = luacom.config.abort_on_error
  luacom.config.abort_on_error = false
  luacom.config.last_error = nil
  if fso:FolderExists( strPath ) then
    fsoObject = fso:GetFolder( strPath )
    tblAttr.mode = "directory"
  elseif fso:FileExists( strPath ) then
    fsoObject = fso:GetFile( strPath )
    tblAttr.mode = "file"
  end
  if fsoObject then
    for j, k in pairs ({ path="Path"; shortpath="ShortPath"; name="Name"; shortname="ShortName"; type="Type"; size="Size";
          created="DateCreated"; modified="DateLastModified"; accessed="DateLastAccessed"; attributes="Attributes"; }) do
      tblAttr[j] = fsoObject[k]
    end
    luacom.DateFormat = "table"
    tblAttr.change       = intTime( fsoObject.DateCreated or {} )
    tblAttr.modification = intTime( fsoObject.DateLastModified or {} )
    tblAttr.access       = intTime( fsoObject.DateLastAccessed or {} )
    luacom.DateFormat = "string"
  end
  if luacom.config.last_error then
    fhMessageBox("\n FileAttributes function failed. \n")
  end
  luacom.config.abort_on_error = oldAbort_on_Error
  return tblAttr
end -- function FileAttributes

Usage of File Attributes

local tblAttr = FileAttributes( "C:\\ProgramData\\Calico Pie\\Family Historian\\Flags\\Flags.fha" )

for _, strItem in ipairs ({ "path"; "shortpath"; "name"; "shortname"; "mode"; "type"; "size"; "created"; "change"; "modified"; "modification"; "accessed"; "access"; "attributes"; }) do
  print( strItem, tblAttr[strItem] )
end

local tblAttr = FileAttributes( "C:\\ProgramData\\Calico Pie\\Family Historian\\Flags" )
for _, strItem in ipairs ({ "path"; "shortpath"; "name"; "shortname"; "mode"; "type"; "size"; "created"; "change"; "modified"; "modification"; "accessed"; "access"; "attributes"; }) do
  print( strItem, tblAttr[strItem] )
end

That produces the following values:

path            C:\ProgramData\Calico Pie\Family Historian\Flags\Flags.fha
shortpath       C:\PROGRA~3\CALICO~1\Family Historian\Flags\Flags.fha
name            Flags.fha
shortname       Flags.fha
mode            file
type            FHA File
size            398.0
created         16/03/2018 19:49:52
change          1521229792
modified        01/11/2020 12:53:17
modification    1604235197
accessed        02/04/2022 09:52:04
access          1648889524
attributes      32.0
 
path            C:\ProgramData\Calico Pie\Family Historian\Flags
shortpath       C:\PROGRA~3\CALICO~1\Family Historian\Flags
name            Flags
shortname       Flags
mode            directory
type            File folder
size            398.0
created         16/03/2018 19:49:52
change          1521229792
modified        21/11/2020 22:05:57
modification    1605996357
accessed        02/04/2022 12:38:23
access          1648899503
attributes      16.0

Code for Path Attributes

This only works for ƒh V7, and provides the attributes of all files and optionally recursively all subfolders within a folder.

require("fhFileUtils")

function PathAttributes( strFolder, doRecurse )

  local function intTime( tblT )	-- Convert Y/M/D H:M:S to UNIX epoch seconds past 1/1/1970
    return os.time({ year=tblT.Year or 1970; month=tblT.Month or 1; day=tblT.Day or 1; hour=tblT.Hour or 0; min=tblT.Minute or 0; sec=tblT.Second or 0; })
  end

  local tblFolder = fhFileUtils.getFolderContents( strFolder, doRecurse )
  if not tblFolder then tblFolder = {} end
  for _, tblAttr in ipairs ( tblFolder ) do
    local strPath = tblAttr.path
    local fsoObject
    local oldAbort_on_Error = luacom.config.abort_on_error
    luacom.config.abort_on_error = false
    luacom.config.last_error = nil
    if fhFileUtils.fso:FolderExists( strPath ) then
      fsoObject = fhFileUtils.fso:GetFolder( strPath )
      tblAttr.mode = "directory"
    else
      fsoObject = fhFileUtils.fso:GetFile( strPath )
      tblAttr.mode = "file"
    end
    luacom.DateFormat = "table"
    tblAttr.change       = intTime( fsoObject.DateCreated or {} )
    tblAttr.modification = intTime( fsoObject.DateLastModified or {} )
    tblAttr.access       = intTime( fsoObject.DateLastAccessed or {} )
    luacom.DateFormat = "string"
    tblAttr.accessed  = fsoObject.DateLastAccessed
    if luacom.config.last_error then
      fhMessageBox("\n PathAttributes function failed. \n")
    end
    luacom.config.abort_on_error = oldAbort_on_Error
  end

  return tblFolder

end -- function PathAttributes

Usage of Path Attributes

local tblFolder = PathAttributes( "C:\\ProgramData\\Calico Pie\\Family Historian\\Autotext", true )

for _, tblAttr in ipairs ( tblFolder ) do
  for _, strItem in ipairs ({ "path"; "shortpath"; "name"; "shortname"; "mode"; "type"; "size"; "created"; "change"; "modified"; "modification"; "accessed"; "access"; "attributes"; }) do
    print( strItem, tblAttr[strItem] )
  end
  print(" ")
end

That produces values such as the following:

path            C:\ProgramData\Calico Pie\Family Historian\Autotext\Research
shortpath       C:\PROGRA~3\CALICO~1\Family Historian\Autotext\Research
name            Research
shortname       Research
mode            directory
type            File folder
size            1350.0
created         30/01/2021 15:56:42
change          1612022202
modified        30/01/2021 15:56:57
modification    1612022217
accessed        02/04/2022 12:38:23
access          1648899503
attributes      16.0
 
path            C:\ProgramData\Calico Pie\Family Historian\Autotext\Research\Log.ftf
shortpath       C:\PROGRA~3\CALICO~1\Family Historian\Autotext\Research\Log.ftf
name            Log.ftf
shortname       Log.ftf
mode            file
type            Family Historian Text Format
size            318.0
created         30/01/2021 15:56:57
change          1612022217
modified        02/06/2020 20:57:02
modification    1591127822
accessed        08/03/2022 19:48:22
access          1646768902
attributes      32.0