| 
| 
| 
| #207192 - 2013-04-24 09:18 PM  Re: Just Sharing - Adding Printers based on computer name via INI
[Re:  Glenn Barnas] |  
| Glenn Barnas   KiX Supporter
 
       
   Registered:  2003-01-28
 Posts: 4401
 Loc:  New Jersey
 | 
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.
 This is on an older P4 3.2GHz w/ Win-8. On my Win-7 test system, I get    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.iniAll testing was done on local storage - 72K RPM SATA. Interestingly, running over the network showed better performance using IniArray.    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.iniWin-8 PC on Network drive (100Mbps)
 Win-7 Test PC on Network drive(Gig-E)    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.iniJust thought this was interesting.    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
 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:
 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!    |  
| Top |  |  |  |  
| 
| 
| #207201 - 2013-04-25 06:18 AM  Re: Just Sharing - Adding Printers based on computer name via INI
[Re:  Lonkero] |  
| Lonkero   KiX Master Guru
 
       
 Registered:  2001-06-05
 Posts: 22346
 Loc:  OK
 | 
did try couple different ones... it's still just as slow.I eliminated the multidim array, in hopes of some improvement. did a separate index array for the keys... still not improving. I am starting to think it might not actually have anything to do with arrays but UDF processing itself.
 
 here is my tweaked one...
 
 
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
? "finished" ?
get $
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, 49]				; 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_[0]			; return an empty array
    Exit @ERROR					; exit if error opening
  EndIf
  ReDim $a_INIDATA_[49], $_aKey[49], $_aData[49]	; 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[$_J]	; trim data array to size
          ReDim Preserve $_aKey[$_J]	; trim data array to size
dim $sps[1]
$sps[0]=$_aKey
$sps[1]=$_aData
          $a_INIDATA_[$_I][1] = $sps
          ReDim $_aKey[49]			; create the data array for the new section
          ReDim $_aData[49]			; 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 49 = 0 And $_I > 0
        ReDim Preserve $a_INIDATA_[$_I + 50] ; increase the section input buffer
      EndIf
dim $indx[1]
$indx[0] = Split(SubStr($_, 2), ']')[0]
      $a_INIDATA_[$_I] = $indx
    Else
      If Not InStr(';#', Left($_, 1)) And Len($_) > 2
        $_aDat = Split($_, '=')			; break into array
        $_J = $_J + 1				; increment the data index
        If $_J Mod 49 = 0 And $_J > 0
          ReDim Preserve $_aData[$_J + 50]	; increase the key input buffer
        EndIf
        $_aKey[$_J] = $_aDat[0]		; Store the value
        $_aData[$_J] = $_aDat[1]		; Store the value
      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 $_aKey[$_J]		; trim data array to size
      ReDim Preserve $_aData[$_J]		; trim data array to size
dim $sps[1]
$sps[0]=$_aKey
$sps[1]=$_aData
      $a_INIDATA_[$_I][1] = $sps
    Else
      ReDim Preserve $_aData[0]
      ReDim Preserve $_aKey[0]		; trim data array to size
dim $sps[1]
$sps[0]=$_aKey
$sps[1]=$_aData
      $a_INIDATA_[$_I][1] = $sps
    EndIf
    ReDim Preserve $a_INIDATA_[$_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_)
  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_[$_I][0]
  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_[$_I][1]			; Extract the key/value array
  ; Create a Key index for the requested section
   If Not $_Key
    $readiniarray=join($_aData[0],chr(10))
    exit 0
   endif
   if 0>ascan($_aData[0],$_Key)
    exit 2
   endif
   $ReadIniArray = $_aData[1][ascan($_aData[0],$_Key)]
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]			; create data array
      $_aData[0] = $_Key			; key
      $_aData[1] = $_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]			; 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)]
      For $_J = 0 to UBound($_aData)
        $_aKeyIdx[$_J] = $_aData[$_J][0]	; 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) + 1		; find next key index
          ReDim Preserve $_aData[$_J]	; create data array
dim $dats[1]
$dats[0] = $_Key		; key
          $dats[1] = $_Data		; data
          $_aData[$_J] = $dats
          $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[$_J][1] = $_Data
        ; If the data is null, write empty key and data values (delete key)
        Else
dim $dats[1]
          $_aData[$_J] = $dats			; delete key
        EndIf
        $a_INIDATA_[1, $_I] = $_aData		; update the array
      EndIf
    EndIf
  EndIf
  Exit 0
EndFunction
_________________________! download KiXnet |  
| Top |  |  |  |  
| 
| 
| #207203 - 2013-04-25 11:22 AM  Re: Just Sharing - Adding Printers based on computer name via INI
[Re:  Lonkero] |  
| ChristopheM   Hey THIS is FUN
 
       
 Registered:  2002-05-13
 Posts: 311
 Loc:  STRASBOURG, France
 | 
Hello,
 done a new version of functions with a handle instead of an array (and prefix all functions with CM). the script tests files with 3 methods :
 - time1 uses ReadProfileString
 - time2 uses my own functions CMIniArray, CMReadIniArray, etc...
 - time3 uses IniArray, ReadIniArray, etc...
 
 here is the complete code for test (just create a subdir called "test" with inifiles or change the content of $arrInifiles) :
 .break on
$=setoption( "explicit", "on" )
dim $arrInifiles, $inifile, $tmpfile, $size, $ini, $start, $d1, $d2, $d3
dim $arrSections, $arrKeys, $section, $key, $value
$arrInifiles =
    @scriptdir+"\test\file010.ini",
    @scriptdir+"\test\file020.ini",
    @scriptdir+"\test\file030.ini",
    @scriptdir+"\test\file040.ini",
    @scriptdir+"\test\file050.ini",
    @scriptdir+"\test\file060.ini",
    @scriptdir+"\test\file070.ini",
    @scriptdir+"\test\file080.ini",
    @scriptdir+"\test\file090.ini",
    @scriptdir+"\test\file100.ini",
    ""
right( "        size", 8 )
right( "        time1",8 )
right( "        time2",8 )
right( "        time3",8 )
"  filename"
?
for each $inifile in $arrInifiles
    if $inifile
        $tmpfile = @scriptdir+"\"+@ScriptName+".tmp"
        $size = GetFileSize($inifile)
        ;-- read with ReadProfileString --
        $start = @TICKS
        COPY $inifile $tmpfile
        $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
        $d1 = @TICKS - $start
        ;-- read with ini functions (version Christophe) --
        $start = @TICKS
        $ini = CMIniArray( $inifile )
        if not @error
            $arrSections = CMINISections($ini)
            for each $section in $arrSections
                $arrKeys = CMINIKeys( $ini, $section )
                for each $key in $arrKeys
                    $value = CMReadIniArray( $ini, $section, $key )
                next
            next
        endif
        $ = CMCloseIniArrayHandle( $ini )
        $d2 = @TICKS - $start
        $ = CMCloseIniArrayHandle( $ini )
        ;-- read with ini functions (version Glenn) --
        $start = @TICKS
        $ini = IniArray( $inifile )
        if not @error
            $arrSections = INISections($ini)
            for each $section in $arrSections
                $arrKeys = INIKeys( $ini, $section )
                for each $key in $arrKeys
                    $value = ReadIniArray( $ini, $section, $key )
                next
            next
        endif
        $d3 = @TICKS - $start
        right( "        "+$size,8 )
        right( "        "+$d1,  8 )
        right( "        "+$d2,  8 )
        right( "        "+$d3,  8 )
        "  "
        $inifile
        ?
        DEL $tmpfile
    endif
next
;-------------------------------------------------------------------------------
; set of function to read in a ini file (version Christophe)
;-------------------------------------------------------------------------------
; internal function
; returned handle is the index of the entry in a global array
; each item in the array is an array of 4 values :
;   entry 0 is a boolean (handle used or not)
;   entry 1 is the name of the ini file
;   entry 2 is the number of sections found in the ini file
;   entry 3 is an array of sections structures
;
; each section structure is an array of 3 values :
;   entry 0 is the name of the section
;   entry 1 is the number of keys in the section
;   entry 2 is an array of keys structures
;
; each key structure is an array of 2 values :
;   entry 0 is the name of the key
;   entry 1 is the value
;-------------------------------------------------------------------------------
function CMGetIniArrayHandle( $inifilename )
    if not IsDeclared( $_IniArrayGlobalHandle )
        ;-- initialize global internal variables --
        global $_IniArrayGlobalHandleNb            $_IniArrayGlobalHandleNb = -1
        global $_IniArrayGlobalHandleInc        $_IniArrayGlobalHandleInc = 32
        global $_IniArrayGlobalHandle[$_IniArrayGlobalHandleInc]
    endif
    dim $i
    for $i = 0 to $_IniArrayGlobalHandleNb
        if ($_IniArrayGlobalHandle[$i][0]=1) and ($_IniArrayGlobalHandle[$i][1]=$inifilename)
            ;-- inifile already loaded : reuse the same handle --
            $CMGetIniArrayHandle = $i
            exit 0
        endif
        if ($_IniArrayGlobalHandle[$i][0]=0)
            ;-- use a free existing handle --
            $_IniArrayGlobalHandle[$i] = 1, $inifilename, 0, ""
            $CMGetIniArrayHandle = $i
            exit 0
        endif
    next
    ;-- use a new handle --
    $_IniArrayGlobalHandleNb = $_IniArrayGlobalHandleNb + 1
    if $_IniArrayGlobalHandleNb > UBound($_IniArrayGlobalHandle)
        redim preserve $_IniArrayGlobalHandle[ UBound($_IniArrayGlobalHandle)+$_IniArrayGlobalHandleInc ]
    endif
    $_IniArrayGlobalHandle[$_IniArrayGlobalHandleNb] = 1, $inifilename, 0, ""
    $CMGetIniArrayHandle = $_IniArrayGlobalHandleNb
endfunction
;-------------------------------------------------------------------------------
; external function
;-------------------------------------------------------------------------------
function CMCloseIniArrayHandle( $inihandle )
    if $inihandle < 0                           exit    endif
    if $inihandle > $_IniArrayGlobalHandleNb    exit    endif
    if $_IniArrayGlobalHandle[$inihandle][0]=1
        if $_IniArrayGlobalHandle[$inihandle][2]>0
            dim $i
            for $i = 0 to UBound( $_IniArrayGlobalHandle[$inihandle][3] )
                $_IniArrayGlobalHandle[$inihandle][3][$i][1] = 0
                $_IniArrayGlobalHandle[$inihandle][3][$i][2] = ""
            next
        endif
        $_IniArrayGlobalHandle[$inihandle] = 0, "", 0, ""
    endif
endfunction
function CMIniArray( $inifilename )
    dim $fHandle                                         ; file pointer
    $CMIniArray = -1
    $fHandle = FreeFileHandle()                          ; locate an available file handle
    if not $fHandle
        exit 1                                           ; none available - exit
    endif
    ;-- try to open file for read into a memory structure --
    if Open($fHandle, $inifilename, 2)<>0                ; open the file for read
        exit 2                                           ; error opening - exit
    endif
    dim $inihandle
    $inihandle = CMGetIniArrayHandle( $inifilename )
    dim $inc        $inc = 128
    dim $arrSections[$inc], $nbSection, $section
    dim $arrKeys[$inc], $nbKey
    dim $_, $ch, $i
    $nbSection    = -1
    do                                                   ; loop through the file contents
        $_ = Trim(ReadLine($fHandle))                    ; remove leading/trailing spaces
        if $_
            $ch = Left($_, 1)
            select
                case $ch="["
                    $ch = Right($_, 1)
                    if $ch="]"                           ; found a section
                        If $nbSection > -1               ; process prior section data, if any
                            gosub _CMIniArray_SavePreviousSection
                        endif
                        $nbKey = -1
                        $nbSection = $nbSection + 1      ; increment the section index
                        if $nbSection > UBound($arrSections)
                            redim Preserve $arrSections[ UBound($arrSections)+$inc ]
                        endif
                        $section = SubStr($_, 2, len($_)-2 )
                    endif
                case $ch=";"                             ; comment line
                case $ch="#"                             ; comment line
                case Len($_) > 2
                    if $nbSection > -1
                        $nbKey = $nbKey + 1
                        if $nbKey > UBound($arrKeys)
                            redim preserve $arrKeys[ UBound($arrKeys)+$inc ]
                        endif
                        $i = instr( $_, "=" )
                        if $i
                            $arrKeys[ $nbKey ] = substr( $_, 1, $i-1), substr( $_, $i+1 )
                        else
                            $arrKeys[ $nbKey ] = $_, ""
                        endif
                    endif
                case 1
            endselect
        endif
    Until @ERROR                                         ; done with input data
    $_ = Close($fHandle)                                 ; close the file
    ;-- process the last/only section --
    If $nbSection > -1
        gosub _CMIniArray_SavePreviousSection
        redim preserve $arrSections[$nbSection]
        $_IniArrayGlobalHandle[$inihandle][2] = $nbsection + 1
        $_IniArrayGlobalHandle[$inihandle][3] = $arrSections
    else
        $_IniArrayGlobalHandle[$inihandle][2] = 0
        $_IniArrayGlobalHandle[$inihandle][3] = ""
    endif
    $CMIniArray = $inihandle                             ; return the array
    Exit 0                                               ; exit success
:_CMIniArray_SavePreviousSection
    if $nbKey=-1
        $arrSections[$nbSection] = $section, 0, ""
    else
        redim preserve $arrKeys[ $nbKey ]
        $arrSections[$nbSection] = $section, ($nbKey+1), $arrKeys
    endif
    return
endfunction
function CMReadIniArray( $inihandle, OPTIONAL $Section, OPTIONAL $Key )
    ;-- in the code --
    ;   $_IniArrayGlobalHandle[$inihandle][2]                     number of sections
    ;   $_IniArrayGlobalHandle[$inihandle][3]                     array of sections
    ;   $_IniArrayGlobalHandle[$inihandle][3][$sectionindex][1]   number of keys in a section
    ;   $_IniArrayGlobalHandle[$inihandle][3][$sectionindex][2]   array of (key, value) in a section
    ;
    ; If the Section is null, return a delimited string of Sections [same as ReadProfileString(file)]
    $CMReadIniArray = ""
    If Not $Section
        if $_IniArrayGlobalHandle[$inihandle][2] > 0
            ;-- enum section name in the inifile --
            for each $section in $_IniArrayGlobalHandle[$inihandle][3]
                $CMReadIniArray = $CMReadIniArray + $section[0] + chr(10)
            next
        endif
        Exit 0
    endif
    ; Search the index for a section
    dim $sectionindex, $i, $item
    $sectionindex = -1
    if $_IniArrayGlobalHandle[$inihandle][2] > 0
        for $i = 0 to UBound($_IniArrayGlobalHandle[$inihandle][3])
            if $_IniArrayGlobalHandle[$inihandle][3][$i][0]=$section
                $sectionindex = $i
            endif
        next
    endif
    If $sectionindex < 0 Exit 2 endif                    ; section not found - Exit
    If Not $Key
        ;-- enum key name in the section --
        if $_IniArrayGlobalHandle[$inihandle][3][$sectionindex][1]<>0
            for each $item in $_IniArrayGlobalHandle[$inihandle][3][$sectionindex][2]
                $CMReadIniArray = $CMReadIniArray + $item[0] + chr(10)
            next
        endif
        Exit 0
    endif
    for each $item in $_IniArrayGlobalHandle[$inihandle][3][$sectionindex][2]
        if $item[0]=$key
            $CMReadIniArray = $item[1]
            exit 0                                       ; key found
        endif
    next
    exit 2                                               ; key not found
endfunction
function CMINISections( $inihandle )
    $CMINISections = CMReadIniArray( $inihandle )
    if Len($CMINISections) > 0
        $CMINISections=split($CMINISections,chr(10))
    endif
endfunction
function CMINIKeys( $inihandle, $section )
    $CMINIKeys = CMReadIniArray( $inihandle, $section )
    if Len($CMINIKeys) > 0
        $CMINIKeys=split($CMINIKeys,chr(10))
    endif
endfunction
;-------------------------------------------------------------------------------
; set of function to read in a ini file (version Glenn)
;-------------------------------------------------------------------------------
;FROM http://www.kixtart.org/forums/ubbthreads.php?ubb=showflat&Number=202790#Post202790
Function IniArray($_fSrcFile, OPTIONAL $_aDataWrite)
    Dim $_                                    ; temp var
    Dim $_Fp                                ; file pointer
    Dim $_I, $_J                            ; index pointers
    Dim $_Sect                                ; Section Name
    Dim $_aDat                                ; Data pair
    Dim $_aSect[1,0], $_aData[1, 0]            ; Section & Data Arrays
    ; 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 VarType($_aDataWrite)  > 0                        ; Write the array to the INI file and exit
        If VarType($_aDataWrite) < 8192                  ; data but 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 Exit @ERROR EndIf                      ; exit if error opening
        ; Write the section data. If no data exists in the section, do not write anything!
        For $_I = 0 to UBound($_aDataWrite, 2)
            $_Sect  = $_aDataWrite[0, $_I]               ; Section name to write
            $_aData = $_aDataWrite[1, $_I]               ; Data array
            If UBound($_aData, 2) > -1                   ; create Sect and write data if data is present
                $_ = '[' + $_Sect + ']' + @CRLF          ; section name
                For $_J = 0 to UBound($_aData, 2)        ; key/data pairs
                    If $_aData[1, $_J]                   ; only write keys that have non-null data
                        $_ = $_ + $_aData[0, $_J] + '=' + $_aData[1, $_J] + @CRLF
                    EndIf
                Next
                $_ = WriteLine($_Fp, $_)                 ; write the output line
                If @ERROR Exit @ERROR EndIf              ; exit if error writing
            EndIf
        Next
        $_ = Close($_Fp)                                 ; close the file
        ReDim $_aData[1, 0]                              ; clear array
        ; exit 0 ; do not exit here to force a re-read of the freshly written data
    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 Exit @ERROR EndIf                          ; exit if error opening
    Do                        ; loop through the file contents
        $_ = Trim(ReadLine($_Fp))                        ; remove leading/trailing spaces
        If Left($_, 1) = '['                             ; found a section
            If $_I >= 0                                  ; process prior section data, if any
                $_aSect[1, $_I] = $_aData
                ReDim $_aData[1, 0]
                $_J = -1
            EndIf
            $_I = $_I + 1                                ; increment the section index
            ReDim Preserve $_aSect[1, $_I]
            $_aSect[0, $_I] = Split(SubStr($_, 2), ']')[0]
        Else
            If Not Left($_, 1) = ';' And Not Left($_, 1) = '#' And Len($_) > 2
                $_aDat = Split($_, '=')                  ; break into array
                $_J = $_J + 1                            ; increment the data index
                ReDim Preserve $_aData[1, $_J]
                $_aData[0, $_J] = $_aDat[0]              ; Store the data
                $_aData[1, $_J] = $_aDat[1]              ; Store the data
            EndIf
        EndIf
    Until @ERROR                                         ; done with input data
    $_ = Close($_Fp)                                     ; close the file
    ; process the last/only section
    If $_I >= 0
        $_aSect[1, $_I] = $_aData
    EndIf
    $IniArray = $_aSect                                  ; return the array
    Exit 0                                               ; exit success
EndFunction
Function ReadIniArray($_aIniFile, OPTIONAL $_Section, OPTIONAL $_Key)
    ; exit immediately if the data format is invalid
    If VarType($_aIniFile) < 8192                        ; data but not an array - exit!
        Exit 87
    EndIf
    Dim $_aSectIdx[UBound($_aIniFile, 2)]                ; Section Index Array
    Dim $_I, $_J                                         ; Index pointers
    Dim $_aData                                          ; Array of Key/Data pairs
    ; Create a section index array
    For $_I = 0 to UBound($_aIniFile, 2)
        $_aSectIdx[$_I] = $_aIniFile[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 = $_aIniFile[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
;Modified FROM http://www.kixtart.org/forums/ubbthreads.php?ubb=showflat&Number=203126#Post203126
function INISections($array)
    $INISections = readiniarray($array)
    if LEN($INISections) > 0
        $INISections=split($INISections,chr(10))
    endif
endfunction
function INIKeys($array,$section)
    $INIKeys = readiniarray($array,$section)
    if LEN($INIKeys) > 0
        $INIKeys=split($INIKeys,chr(10))
    endif
endfunction
On a Intel E5200 (Dual-Core 2.5Ghz) with 2Gb, the results are :
     size   time1   time2   time3  filename
      91      15       0       0  .\test\file010.ini
    2019       0      16       0  .\test\file020.ini
    7553      16      47      46  .\test\file030.ini
   15173      94    1110    2484  .\test\file040.ini
   28149     187    1704    2296  .\test\file050.ini
   34527      47     250     500  .\test\file060.ini
   43179      94    1031    1938  .\test\file070.ini
   69058     125     515    1125  .\test\file080.ini
  103587     235     797    1922  .\test\file090.ini
  138116     375    1062    2969  .\test\file100.iniOn a Intel Pentium 4 (Mono-Core 2.4Ghz) with 1Gb, the results are :
     size   time1   time2   time3  filename
      91       0       0       0  .\test\file010.ini
    2019      15      16      16  .\test\file020.ini
    7553      31      94      93  .\test\file030.ini
   15173     203    2563    6094  .\test\file040.ini
   28149     468    3625    6250  .\test\file050.ini
   34527     125     610    1328  .\test\file060.ini
   43179     218    2532    5015  .\test\file070.ini
   69058     360    1281    3281  .\test\file080.ini
  103587     781    1938    5969  .\test\file090.ini
  138116    1328    2562    9641  .\test\file100.iniReadProfileString is always the faster with local file !!!
 
 I use a global array to allocate handle (with associated data). redim is automatic if many differents ini files are used.
 I have not tested all cases for CMReadIniArray and I suppress the optional parameter for write in CMIniArray.
 Code is not very easy to read because of use of array of array of array ... but it seems to be fast.
 
 Not sure i'll use it in my login script because all procedures are already written to copy inifile locally before using ReadProfileString and delete temp file when finished.
 But it was a good exercize for fun
   
_________________________Christophe
 |  
| Top |  |  |  |  
 Moderator:  Glenn Barnas, NTDOC, Arend_, Jochen, Radimus, Allen, ShaneEP, Ruud van Velsen, Mart
 
 | 
| 
 
| 0 registered
and 793 anonymous users online. 
 | 
 |  |