OK - I'm starting to wonder about the performance of arrays in Kix...

I modified the IniArray library to use a single, global array. No more passing arrays to/from the functions. While I can determine that this is slightly faster than passing the arrays, it is (surprisingly) nowhere near the direct read performance of ReadProfileString.

Taking your test code and my new function with Global arrays, I get the following results. The one difference in my code is that I separated out the array load time (LTime) from the ReadIniArray enumerations.
 Code:
    size   LTime   time1   time2  filename
    1199      16       0      16  .\test1.ini
    7131      31     141      62  .\test2.ini
   19989      47     687     188  .\test3.ini
   63231     141    4375     890  .\test4.ini
   91229     219   12062    1703  .\test5.ini
This is on an older P4 3.2GHz w/ Win-8. On my Win-7 test system, I get
 Code:
    size   LTime   time1   time2  filename
    1199       0      16       0  .\test1.ini
    7131      16     141      78  .\test2.ini
   19989      16     391     187  .\test3.ini
   63231      78    2484    1032  .\test4.ini
   91229     109    7125    2109  .\test5.ini
All testing was done on local storage - 72K RPM SATA. Interestingly, running over the network showed better performance using IniArray.
Win-8 PC on Network drive (100Mbps)
 Code:
    size   LTime   time1   time2  filename
    1199       0      16      47  .\test1.ini
    7131      31     140     438  .\test2.ini
   19989      62     688    2156  .\test3.ini
   63231     156    4360   16625  .\test4.ini
   91229     250   12109   34672  .\test5.ini
Win-7 Test PC on Network drive(Gig-E)
 Code:
    size   LTime   time1   time2  filename
    1199      16       0      47  .\test1.ini
    7131      15     141     328  .\test2.ini
   19989      47     562    1000  .\test3.ini
   63231     140    2704    4875  .\test4.ini
   91229     203    7047    8985  .\test5.ini
Just thought this was interesting.

I think I'll drop the Global Array model for now since the performance benefit is slight. The IniArray library has benefit for network based I/O and for larger files.

Glenn

Here's the modified test code and global array version of IniArray:
 Code:
Break On

Dim $

$ = SetOption('Explicit', 'On')
$ = SetOption('WrapAtEOL', 'On')
$ = SetOption('NoVarsInStrings', 'On')

If Not Exist('.\Test1.ini')
  'Generating test files' 
  GenIni('.\Test1.ini', 10, 5)
  '!'
  GenIni('.\Test2.ini', 50, 8)
  '!'
  GenIni('.\Test3.ini', 100, 15)
  '!'
  GenIni('.\Test4.ini', 250, 18)
  '!'
  GenIni('.\Test5.ini', 500, 12)
  'Done!' ? ?
EndIf
  
'Press a key to continue ' Get $ ?

dim $arrInifiles, $inifile, $tmpfile, $ini, $arrSections, $arrKeys, $section, $key, $d0, $d1, $d2, $Size, $Start, $Value

$arrInifiles =
  ".\test1.ini",
  ".\test2.ini",
  ".\test3.ini",
  ".\test4.ini",
  ".\test5.ini"

right( "        size",8 )
right( "        LTime",8 )
right( "        time1",8 )
right( "        time2",8 )
"  filename"
?
for each $inifile in $arrInifiles
  if $inifile
    $tmpfile = @scriptdir+"\"+@ScriptName+".tmp"
    COPY $inifile $tmpfile

    $size = GetFileSize($tmpfile)

    ;-- read with ini functions --
    $start = @TICKS
    $ini = IniArray($tmpfile)
    $d0 = @TICKS - $Start
    $start = @TICKS
    $arrSections = Split(ReadIniArray(''), Chr(10))
    for each $section in $arrSections
      $arrKeys = Split(ReadIniArray($section), Chr(10))
      for each $key in $arrKeys
        $value = ReadIniArray($section, $key )
      next
    next
    $d1 = @TICKS - $start

    ;-- read with ReadProfileString --
    $start = @TICKS
    $arrSections = ReadProfileString( $tmpfile, "", "" )
    $arrSections = split($arrSections, chr(10) )
    for each $section in $arrSections
      if $section
        $arrKeys = ReadProfileString( $tmpfile, $section, "" )
        $arrKeys = split($arrKeys, chr(10) )
        for each $key in $arrKeys
          if $key
            $value = ReadProfileString( $tmpfile, $section, $key )
          endif
        next
      endif
    next
    $d2 = @TICKS - $start

    right( "        "+$size,8 )
    right( "        "+$d0,8 )
    right( "        "+$d1,8 )
    right( "        "+$d2,8 )
    "  "
    $inifile
    ?

    DEL $tmpfile
  endif
next


Function GenIni($_File, $_S, $_MKey)

  Dim $_, $_X, $_Y
  Dim $_Section, $_Key, $_Data

  Del $_File

  SRnd(@MSECS)
  For $_X = 1 to $_S				; Sections
    For $_Y = 1 to 1 + Rnd($_MKey)		; Keys
      $_Section = 'SECTION_' + Right('0000' + $_X, 4)
      $_Key = 'Key_' + Right('00' + $_Y, 2)
      $_Data = Left('The quick brown fox jumped over the lazy dog.', Rnd(30))
      $_ = WriteProfileString($_File, $_Section, $_Key, $_Data)
    Next
    If $_X Mod 50 = 0 '.' EndIf
  Next

  Exit 0

EndFunction






;;
;;======================================================================
;;
;;FUNCTION       IniArray()
;;		  ReadIniArray()	- subfunction for reading array
;;		  WriteIniArray()	- subfunction for writing array
;;
;;ACTION         Reads INI file into an array;
;;		 Writes array to INI format file & reloads the array with fresh data
;;		  ReadIniArray() reads a Section:Key:Data set from the array
;;		  WriteIniArray() writes a Section:Key:Data set to the array
;;
;;AUTHOR         Glenn Barnas
;;
;;VERSION        1.0 / 2011-08-02
;;		 1.1 / 2013-04-17 - improve file load on large files
;;		 1.2 / 2013-04-20 - bugfixes:
;;				    Read empty section or file, write empty section, 
;;				WriteIniArray() - fix error if duplicate write of null data
;;				    Added Options to IniArray for Write to add blank
;;				    lines between sections
;;
;;SYNTAX         IniArray(filename, Action [,options])
;;
;;PARAMETERS     filename - REQUIRED - the name of the INI file to read/write
;;
;;		 action	  - OPTIONAL - "R" or "W" for Read or Write - Defaults to Read
;;
;;		 options  - OPTIONAL - bitwise settings to control output formatting
;;		      Value	Mode	Description
;;			1	Write	Adds blank lines between Sections when true
;;			2	Write	Suppress the array reload on write, useful when
;;					no further INI manipulation is planned.
;;
;;REMARKS        Reads an entire INI file into an array for processing. There is no limit
;;		 on the size of the INI file, other than any Kix limits on general file sizes.
;;		 On read, blank lines and comments (lines that begin with ";" or "#") are
;;		 ignored. On write, only sections that contain data/value pairs are written,
;;		 mimicing the action of WriteProfileString(). Similarly, only Keys that
;;		 have non-null values are written.
;;
;;		 The global array called $a_INIDATA_ is used for operations and will be declared
;;		 by the first call to IniArray if it was not previously defined.
;;		 
;;		 The secondary functions ReadIniArray() and WriteIniArray() make using the 
;;		 IniArray() UDF as easy to use as ReadProfileString() and WriteProfileString(),
;;		 simply requiring calls to IniArray to load and then save the INI file. The
;;		 Read and Write sub-functions use the same syntax as the ProfileString
;;		 functions but reference the array instead of the INI file. 
;;
;;		 NOTE: During array manipulation, deleted records are set to null and not reused.
;;			Similarly, when a new key/data pair is added, deleted array items are
;;			not reused. When the array is written to disk, the null records are skipped. 
;;		 	When the file is again read, the array will only contain valid data with no
;;			empty records.
;;			WRITING an array causes a RE-READ operation, cleaning the empty records.
;;
;;		 NOTE: IMPORTANT - When using WriteIniArray() to create a new Ini-array, you MUST
;;		       first declare the array via Dim $a_INIARRAY_[1, 0]. This is not necessary
;;		       if you read an INI file first with IniArray(filename).
;; 
;;RETURNS        IniArray: Returns 1 on success or 0 on failure
;;		 Populates a two-dimensional array of two-dimensional arrays. The first element 
;;		 is the section name, the second element is a two-dimensional array consisting of
;;		 the key/data pairs.
;;
;;		 ReadIniArray: returns the data specified by the section/value pair
;;		 WriteIniArray: Returns 1 on success or 0 on failure
;;		 Updates the global array with the section/value/data provided
;;
;;		 Consider the following simple INI file:
;;		  [COLORS]
;;		  Apple=Red
;;		  Lime=Green
;;		  [TASTES]
;;		  Apple=sweet
;;		  Lime=sour
;;
;;		 The call $Rc = IniArray('inifile.ini') would populate the $a_INIDATA_ array
;;		 that contained the following values:
;;		  $a_INIDATA_[0,0] contains "COLORS"
;;		  $a_INIDATA_[1,0] contains an array of data/value pairs from this section
;;		  - extract with $aData = $a_INIDATA_[1,0]
;;		   $aData[0,0] contains "Apple"; $aData[1,0] contains "Red"
;;		   $aData[0,1] contains "Lime"; $aData[1,1] contains "Green"
;;
;;		  $a_INIDATA_[0,1] contains "TASTES"
;;		  $a_INIDATA_[1,1] contains Array of data/value pairs from this section
;;		  - extract with $aData = $a_INIDATA_[1,1]
;;		   $aData[0,0] contains "Apple"; $aData[1,0] contains "Sweet"
;;		   $aData[0,1] contains "Lime"; $aData[1,1] contains "Sour"
;;
;;		  ; the following would return "Sweet", just like ReadProfileString
;;		  $Taste = ReadIniArray('TASTES', 'Apple')
;;
;;
;;DEPENDENCIES   none
;;
;;TESTED WITH    W2K, WXP, W2K3, W2K8, W7
;;
;;EXAMPLES       INI FILE READ:
;;		   $Rc = IniArray('testfile.ini')
;;		   'File contains ' UBound($a_INIDATA_) + 1 ' sections' ?
;;
;;		 ENUMERATE:
;;		   For $I = 0 to UBound($a_INIDATA_, 2)
;;		     $aData = $a_INIDATA_[1, $I]
;;		  
;;		     'Section: ' $a_INIDATA_[0, $I] ' contains ' UBound($aData, 2) + 1 ' Data/Value elements' ?
;;		     ' Press a key: ' get $ ?
;;		   
;;		     For $J = 0 to UBound($aData, 2)
;;		       $J ': ' $aData[0, $J] ' = ' $aData[1, $J] ?
;;		     Next
;;		   Next
;;
;;		  ELEMENT READ:
;;		   ; Return a specific value
;;		   $Value = ReadIniArray('SectionName', 'keyname')
;;		   ; Return an array of all section names
;;		   $aSections = Split(ReadIniArray(''), Chr(10))
;;		   ; Return an array of Keys in a specific section
;;		   $aKeys = Split(ReadIniArray('SectionName'), Chr(10))
;;
;;		  ELEMENT WRITE/UPDATE:
;;		   ; Write a key/value pair in the named section
;;		   $Rc = WriteIniArray('SectionName', 'keyname', 'Data')
;;
;;		  ELEMENT DELETE:
;;		   ; Remove the named key from the defined section
;;		   $Rc = WriteIniArray('SectionName', 'keyname')
;;
;;		  SECTION DELETE:
;;		   ; Remove all key/value pairs from the section, deleting the section
;;		   $Rc = WriteIniArray('SectionName')
;;
;;		  INI FILE WRITE:
;;		   ; Flush the array to the file and then reload the array
;;		   $Rc = IniArray('testfile.ini', "W")
;
Function IniArray($_fSrcFile, OPTIONAL $_DataWrite, OPTIONAL $_Options)

  Dim $_					; temp var
  Dim $_Fp					; file pointer
  Dim $_C, $_I, $_J				; index pointers
  Dim $_AddLine, $_NoRead			; Option Vars
  Dim $_Sect					; Section Name
  Dim $_aDat					; Data pair array
  Dim $_aData[1, 499]				; Section & Data Arrays

  $_NoRead = 0					; perform read after write

  If $_Options
    If $_Options & 1
      $_AddLine = @CRLF
    EndIf
    If $_Options & 2
      $_NoRead = 1				; write & exit w/o re-reading
    EndIf
  EndIf


  ; Obtain a File Handle for Read or Write operations
  ; ============================================================
  $_Fp = FreeFileHandle				; locate an available file handle
  If Not $_Fp
    Exit 1					; none available - exit
  EndIf

  ; WRITE: verify that we have properly formatted data
  ; ============================================================
  If $_DataWrite = 'W'				; Write operation
    If VarType($a_INIDATA_) < 8192		; Not an array - exit!
      Exit 87
    EndIf

    Del $_fSrcFile				; delete any pre-existing file
    $_ = Open($_Fp, $_fSrcFile, 5)		; open the file for write/create
    If @ERROR
      ReDim $a_INIDATA_[1, 0]			; create empty array
      Exit @ERROR				; exit if error opening
    EndIf

    ; Write the section data. If no data exists in the section, do not write anything!
    For $_I = 0 to UBound($a_INIDATA_, 2)
      $_Sect  = $a_INIDATA_[0, $_I]		; Section name to write
      $_aData = $a_INIDATA_[1, $_I]		; Data array
      If UBound($_aData, 2) > -1		; create Sect and write data if data is present
        $_ = '[' + $_Sect + ']' + @CRLF		; section name
        $_C = 0
        For $_J = 0 to UBound($_aData, 2)	; key/data pairs
          If $_aData[1, $_J]			; only write keys that have non-null data
            $_C = 1
            $_ = $_ + $_aData[0, $_J] + '=' + $_aData[1, $_J] + @CRLF
          EndIf
        Next
        If $_C
          $_ = WriteLine($_Fp, $_ + $_AddLine)	; write the output line
	EndIf
        If @ERROR
	  $_ = Close($_Fp)			; close the file
	  Exit @ERROR
	EndIf		; exit if error writing
      EndIf
    Next

    $_ = Close($_Fp)				; close the file
    ReDim $_aData[1, 0]				; clear array

    If $_NoRead
      exit 0					; exit here without a re-read of the freshly written data
    EndIf

  EndIf

  ; declare the INI array if undefined
  If Not IsDeclared($a_INIDATA_)
    Global $a_INIDATA_[1,0]
  EndIf

  ; READ: Load the ini file into an array
  ; ============================================================
  $_I = -1  $_J = -1				; Initialize index pointers
  
  $_ = Open($_Fp, $_fSrcFile, 2)		; open the file for read
  If @ERROR
    ReDim $a_INIDATA_[1, 0]			; return an empty array
    Exit @ERROR					; exit if error opening
  EndIf

  ReDim $a_INIDATA_[1, 499], $_aData[1, 499]	; Prep Section & Data Arrays for Read

  $_ = Trim(ReadLine($_Fp))			; read INI, removing leading/trailing spaces

  While Not @ERROR				; loop through the file contents
    If Left($_, 1) = '['			; found a section

      If $_I >= 0				; process prior section data, if any
        If $_J >= 0
          ReDim Preserve $_aData[1, $_J]	; trim data array to size
          $a_INIDATA_[1, $_I] = $_aData
          ReDim $_aData[1, 499]			; create the data array for the new section
          $_J = -1
        Else
          $_I = $_I - 1				; ignore empty sections
        EndIf
      EndIf

      $_I = $_I + 1				; increment the section index
      If $_I Mod 499 = 0 And $_I > 0
        ReDim Preserve $a_INIDATA_[1, $_I + 500] ; increase the section input buffer
      EndIf
      $a_INIDATA_[0, $_I] = Split(SubStr($_, 2), ']')[0]
    Else
      If Not InStr(';#', Left($_, 1)) And Len($_) > 2
        $_aDat = Split($_, '=')			; break into array
        $_J = $_J + 1				; increment the data index
        If $_J Mod 499 = 0 And $_J > 0
          ReDim Preserve $_aData[1, $_J + 500]	; increase the key input buffer
        EndIf
        $_aData[0, $_J] = $_aDat[0]		; Store the value
        $_aData[1, $_J] = $_aDat[1]		; Store the data
      EndIf
    EndIf

    $_ = Trim(ReadLine($_Fp))			; remove leading/trailing spaces
  Loop						; done with input data

  $_ = Close($_Fp)				; close the file
  $_ = 2					; prep for Not Found exit

  ; process the last/only section
  If $_I >= 0
    If $_J >= 0
      ReDim Preserve $_aData[1, $_J]		; trim data array to size
      $a_INIDATA_[1, $_I] = $_aData
    Else
      ReDim Preserve $_aData[1, 0]
      $a_INIDATA_[1, $_I] = $_aData
    EndIf
    ReDim Preserve $a_INIDATA_[1, $_I]		; trim section array to size
    $_ = 0
  EndIf

  Exit $_					; exit success

EndFunction


Function ReadIniArray(OPTIONAL $_Section, OPTIONAL $_Key)

  Dim $_I, $_J					; Index pointers
  Dim $_aData, $_aSrc				; Array of Key/Data pairs
  Dim $_Cmd
  Dim $_S
  Dim $_

  ; exit immediately if the data format is invalid
  If VarType($a_INIDATA_) < 8192					; data but not an array - exit!
    Exit 87
  EndIf

  ; Get the array size
  $_S = UBound($a_INIDATA_, 2)
  If $_S <= 0
    Exit 87
  EndIf

  Dim $_aSectIdx[$_S]				; Section Index Array

  ; Create a section index array
  For $_I = 0 to $_S
    $_aSectIdx[$_I] = $a_INIDATA_[0, $_I]
  Next

  ; If the Section is null, return a delimited string of Sections [same as ReadProfileString(file)]
  If Not $_Section
    $ReadIniArray = Join($_aSectIdx, Chr(10))
    Exit 0
  EndIf

  ; Search the index for a section
  $_I = aScan($_aSectIdx, $_Section)
  If $_I < 0 Exit 2 EndIf			; section not found - Exit

  $_aData = $a_INIDATA_[1, $_I]			; Extract the key/value array

  ; Create a Key index for the requested section
  Dim $_aKeyIdx[UBound($_aData, 2)]
  For $_J = 0 to UBound($_aData, 2)
    $_aKeyIdx[$_J] = $_aData[0, $_J] 
  Next

  ; If the Key is null, return a delimited string of Keys [same as ReadProfileString(file, section)]
  If Not $_Key
    $ReadIniArray = Join($_aKeyIdx, Chr(10))
    Exit 0
  EndIf

  ; Search the index for a Key
  $_J = aScan($_aKeyIdx, $_Key)
  If $_J < 0 Exit 2 EndIf			; Key not found

  $ReadIniArray = $_aData[1, $_J]

  Exit 0

EndFunction


Function WriteIniArray($_Section, OPTIONAL $_Key, OPTIONAL $_Data)

  ; exit immediately if the data format is invalid
  If VarType($a_INIDATA_) < 8192		; data but not an array - exit!
    Exit 87
  EndIf

  Dim $_aSectIdx[UBound($a_INIDATA_, 2)]	; Section Index Array
  Dim $_I, $_J					; Index pointers
  Dim $_aData					; Key/Data array


  ; Create a section index array
  For $_I = 0 to UBound($a_INIDATA_, 2)
    $_aSectIdx[$_I] = $a_INIDATA_[0, $_I]
  Next

  ; Search the index for a section
  $_I = aScan($_aSectIdx, $_Section)

  ; If the section does not exist and Keydata is present - add the section and key/value pair (new Sect:Key:Data)
  If $_I < 0					; section not found - Add if Data is present
    If $_Key And $_Data
      $_I = 0					; default to empty array
      If $a_INIDATA_[0, 0]
        $_I = UBound($a_INIDATA_, 2) + 1		; find next section index
      EndIf
      ReDim Preserve $a_INIDATA_[1, $_I]		; Add new section
      ReDim $_aData[1, 0]			; create data array
      $_aData[0,0] = $_Key			; key
      $_aData[1,0] = $_Data			; data
      $a_INIDATA_[0, $_I] = $_Section		; section name
      $a_INIDATA_[1, $_I] = $_aData		; section data
    Else
      Exit 0					; nothing to do
    EndIf
  Else						; the section does exist, locate the Key

    ; If the Key is null, delete the section (delete Section)
    If Not $_Key
      ReDim $_aData[1, 0]			; create empty keys array
      $a_INIDATA_[1, $_I] = $_aData		; write to section
      $a_INIDATA_[0, $_I] = ''			; write null section name
    Else
      $_aData = $a_INIDATA_[1, $_I]		; Extract the key/value array
      ; Create a Key index for the requested section
      Dim $_aKeyIdx[UBound($_aData, 2)]
      For $_J = 0 to UBound($_aData, 2)
        $_aKeyIdx[$_J] = $_aData[0, $_J]	; create the index
      Next
      $_J = aScan($_aKeyIdx, $_Key)		; find the key

      ; If the key does not exist, add the key/data (new Key/data)
      If $_J < 0
        If $_Data
          $_aData = $a_INIDATA_[1, $_I]		; array of key/data pairs
          $_J = UBound($_aData, 2) + 1		; find next key index
          ReDim Preserve $_aData[1, $_J]	; create data array
          $_aData[0, $_J] = $_Key		; key
          $_aData[1, $_J] = $_Data		; data
          $a_INIDATA_[1, $_I] = $_aData		; section data
        Else
          Exit 0				; nothing to do (no data)
        EndIf

      Else					; the key exists - either Update or Delete
    
        ; if the data is not null, write the new data (update key)
        If $_Data
          $_aData[1, $_J] = $_Data

        ; If the data is null, write empty key and data values (delete key)
        Else
          $_aData[0, $_J] = ''			; delete key
          $_aData[1, $_J] = ''			; clear data value
        EndIf
        $a_INIDATA_[1, $_I] = $_aData		; update the array
      EndIf

    EndIf

  EndIf

  Exit 0

EndFunction
_________________________
Actually I am a Rocket Scientist! \:D