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