#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: 4396
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. 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 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) 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) 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: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: 309
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.ini On 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.ini ReadProfileString 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 329 anonymous users online.
|
|
|