Что нового

непредусмотренная ситуация в функции _IniReadSectionEx($hFile, $vSection)

vovsla

Осваивающий
Сообщения
607
Репутация
36
в очень известной, функции _IniReadSectionEx
Код:
Func _IniReadSectionEx($hFile, $vSection)
    Local $iSize = FileGetSize($hFile) / 1024
    If $iSize <= 31 Then Return IniReadSection($hFile, $vSection)
    Local $sFRead = FileRead($hFile), $sHold, $xCC, $iNum = 1
    Local $aSplit = StringSplit(StringStripCR($sFRead), @LF)
    For $xCC = 1 To $aSplit[0]
        If StringLeft(StringStripWS($aSplit[$xCC], 7), _
            StringLen(StringStripWS('[' & $vSection & ']', 7))) = StringStripWS('[' & $vSection & ']', 7) Then
            For $kCC = $xCC + 1 To $aSplit[0]
                If StringLeft(StringStripWS($aSplit[$kCC], 8), 1) = '[' Then ExitLoop
                $sHold &= $aSplit[$kCC] & Chr(01)
            Next
            ExitLoop
        EndIf
    Next
    If $sHold = '' Then Return SetError(1, 0, 0)
    $sHold = StringSplit(StringTrimRight($sHold, 1), Chr(01))
    FileWriteLine(@TempDir & '\IniReadSectionTemp' & $iNum & '.ini', '[' & $vSection & ']')
    For $iCC = 1 To $sHold[0]
        If FileGetSize(@TempDir & '\IniReadSectionTemp' & $iNum & '.ini') / 1024 > 25 Then
            $iNum += 1
            FileWriteLine(@TempDir & '\IniReadSectionTemp' & $iNum & '.ini', '[' & $vSection & ']')
        EndIf
        FileWriteLine(@TempDir & '\IniReadSectionTemp' & $iNum & '.ini', $sHold[$iCC])
    Next
    Local $aTemp, $aReplace, $iMax
    For $aCC = 1 To $iNum
        $aTemp = IniReadSection(@TempDir & '\IniReadSectionTemp' & $aCC & '.ini', $vSection)
        If $aCC = 1 Then
            $aReplace = $aTemp
            FileDelete(@TempDir & '\IniReadSectionTemp' & $aCC & '.ini')
        Else ; Array 2 Dimensional Add On
            $iMax = UBound($aReplace, 1) - 1
            ReDim $aReplace[($iMax + 1) + $aTemp[0][0]][2]
            For $bCC = 1 To $aTemp[0][0]
                $aReplace[$bCC + $iMax][0] = $aTemp[$bCC][0]
                $aReplace[$bCC + $iMax][1] = $aTemp[$bCC][1]
            Next
            FileDelete(@TempDir & '\IniReadSectionTemp' & $aCC & '.ini')
        EndIf
    Next
If IsArray($aReplace)=0 Then Return IniReadSection($hFile, $vSection)
    $aReplace[0][0] = UBound($aReplace, 1) - 1
    Return $aReplace
EndFunc

не предусмотрен один момент, что хоть сам файл и большой, в нём может быть множество заремленных строк в результате получается ошибка в строке ReDim $aReplace[($iMax + 1) + $aTemp[0][0]][2] , в которой говорится, что $aReplace не массив, для решения данной проблемы необходимо перед вышеуказанной строкой добавить
Код:
If IsArray($aReplace)=0 Then
FileDelete(@TempDir & '\IniReadSectionTemp' & $aCC & '.ini')
Return IniReadSection($hFile, $vSection)
EndIf

может кому-то пригодится, а может кто-то и предложит более оптимальное решение
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Vovsla [?]
в очень известной, функции _IniReadSectionEx
И чем она известная? У меня есть (точнее сам писал) более простая и не столь перегруженная версия данной функций:

Код:
#include <Array.au3>

$aReadSect = _IniReadSectionEx("Test.ini", "Section", 3)

_ArrayDisplay($aReadSect)

;$iReadMode = 1 -> Do not read comments
;$iReadMode = 2 -> Do not read keys without values but read the comments
;$iReadMode = 3 -> Do not read all except the lines with key=value (as default behaviour of IniReadSection)
Func _IniReadSectionEx($sIniFile, $sSection, $iReadMode=-1)
	Local $aFileReadArr = StringSplit(StringStripCR(FileRead($sIniFile)), @LF)
	If @error Then Return SetError(1, 0, "")
	
	Local $aRetArr[$aFileReadArr[0]+1][2], $iUbound, $iSplitPos, $sKey, $sValue
	
	For $i = 1 To $aFileReadArr[0]
		If $aFileReadArr[$i] = "[" & $sSection & "]" Then
			For $j = $i+1 To $aFileReadArr[0]
				If StringLeft($aFileReadArr[$j], 1) = "[" Then ExitLoop 2
				
				$iSplitPos = StringInStr($aFileReadArr[$j], "=")
				If $iSplitPos < 1 Then $iSplitPos = StringLen($aFileReadArr[$j]) + 1
				
				$sKey = StringLeft($aFileReadArr[$j], $iSplitPos-1)
				$sValue = StringTrimLeft($aFileReadArr[$j], $iSplitPos)
				
				If $sKey = "" Then ContinueLoop
				If $iSplitPos = 0 Then $sValue = ""
				
				Switch $iReadMode
					Case 1 ;Do not read comments
						If StringRegExp($aFileReadArr[$j], "\A(\s+|);") Then ContinueLoop
					Case 2 ;Do not read keys without values but read the comments
						If ($sValue = "" Or $sValue = $aFileReadArr[$j]) And _
							Not StringRegExp($aFileReadArr[$j], "\A(\s+|);") Then ContinueLoop
					Case 3 ;Do not read all except the lines with key=value (as default behaviour of IniReadSection)
						If Not StringRegExp($aFileReadArr[$j], "\A[^;].*=.*$") Then ContinueLoop
				EndSwitch
				
				$aRetArr[0][0] += 1
				
				$aRetArr[$aRetArr[0][0]][0] = $sKey
				$aRetArr[$aRetArr[0][0]][1] = $sValue
			Next
			
			ExitLoop
		EndIf
	Next
	
	ReDim $aRetArr[$aRetArr[0][0]+1][2]
	Return $aRetArr
EndFunc
 
Автор
V

vovsla

Осваивающий
Сообщения
607
Репутация
36
Я другой просто не знал, спасибо за функцию. Может я что-то не понимаю, но в режиме 3 при чтении раздела "Marvell" в ситуации:
Код:
[Marvell]
%mv64xxDesc%=mv64xx_Inst,PCI\VEN_11AB&DEV_6440
%mv64xxDesc%=mv64xx_Inst,PCI\VEN_11AB&DEV_6485

;[NODRV]
;CopyFiles=MoveNODRV
;[MoveNODRV]

;[NODRV.Services]
;
; this is blank to just allow the install to succeed
;
;AddService = , %SPSVCINST_ASSOCSERVICE%   ; null service install

возвращается массив
Код:
[1]|%mv64xxDesc%|mv64xx_Inst,PCI\VEN_11AB&DEV_6440
[2]|%mv64xxDesc%|mv64xx_Inst,PCI\VEN_11AB&DEV_6485
[3]|;CopyFiles|MoveNODRV
[4]|;AddService | , %SPSVCINST_ASSOCSERVICE%   ; null service install

а обычная функция IniReadSection возвращает
Код:
[1]|%mv64xxDesc%|mv64xx_Inst,PCI\VEN_11AB&DEV_6440
[2]|%mv64xxDesc%|mv64xx_Inst,PCI\VEN_11AB&DEV_6485
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Vovsla [?]
в режиме 3 при чтении раздела "Marvell" в ситуации:
....
возвращается массив
Поправил, добавив «[^;]» в выражение RegExp :smile:.


Добавлено:
Сообщение автоматически объединено:

Переделал работу параметров (теперь их можно совмещать через BitOR()), плюс добавил возможность обрезания коментариев у значений ключей:

Код:
#include <Array.au3>

$aReadSect = _IniReadSectionEx("Test.ini", "Marvell", BitOR(1, 8, 16))
_ArrayDisplay($aReadSect)

;$iReadMode:
;			-1, Default -> Read only key=value entries (as default behaviour of IniReadSection)
;
;			The following options can be combined together with BitOR:
;				1 -> Do not read comments
;				8 -> Do not read keys without values
;				16 -> Strip comments in values. This parameter can be added with BitOR to other flags.
Func _IniReadSectionEx($sIniFile, $sSection, $iReadMode=-1)
	Local $aFileReadArr = StringSplit(StringStripCR(FileRead($sIniFile)), @LF)
	
	If @error Then
		Return SetError(1, 0, "")
	EndIf
	
	Local $aRetArr[$aFileReadArr[0]+1][2], $iUbound, $iSplitPos, $sKey, $sValue
	
	For $i = 1 To $aFileReadArr[0]
		If StringRegExp($aFileReadArr[$i], "^\s*\[\Q" & $sSection & "\E\][\s;]*.*") Then
			For $j = $i+1 To $aFileReadArr[0]
				If StringRegExp($aFileReadArr[$j], "^\s*\[[^\]]+\]\s*") Then
					ExitLoop 2
				EndIf
				
				$iSplitPos = StringInStr($aFileReadArr[$j], "=")
				
				If $iSplitPos < 1 Then
					$iSplitPos = StringLen($aFileReadArr[$j]) + 1
				EndIf
				
				$sKey = StringLeft($aFileReadArr[$j], $iSplitPos-1)
				$sValue = StringTrimLeft($aFileReadArr[$j], $iSplitPos)
				
				If $sKey = "" Then
					ContinueLoop
				EndIf
				
				If $iSplitPos = 0 Then
					$sValue = ""
				EndIf
				
				If $iReadMode <= 0 Or Not IsNumber($iReadMode) Then
					If Not StringRegExp($aFileReadArr[$j], "\A[^;].*=.*$") Then
						ContinueLoop
					EndIf
				Else
					If BitAND($iReadMode, 1) = 1 Then
						If StringRegExp($aFileReadArr[$j], "\A(\s+|);") Then
							ContinueLoop
						EndIf
					EndIf
					
					If BitAND($iReadMode, 8) = 8 Then
						If ($sValue = "" Or $sValue = $aFileReadArr[$j]) And Not StringRegExp($aFileReadArr[$j], "\A(\s+|);") Then
							ContinueLoop
						EndIf
					EndIf
					
					If BitAND($iReadMode, 16) = 16 Then
						$sValue = StringRegExpReplace($sValue, ";.*?$", "")
					EndIf
				EndIf
				
				$aRetArr[0][0] += 1
				
				$aRetArr[$aRetArr[0][0]][0] = $sKey
				$aRetArr[$aRetArr[0][0]][1] = $sValue
			Next
			
			ExitLoop
		EndIf
	Next
	
	ReDim $aRetArr[$aRetArr[0][0]+1][2]
	Return $aRetArr
EndFunc
 

VVV

Новичок
Сообщения
2
Репутация
0
при использовании функции указанной в ответе 3, почему-то не возвращается секция D-Link.NTx86.6.1 из ini файла, файл прикрепил
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
VVV
У меня секция D-Link.NTx86.6.1 из Вашего файла возвращается стандартной функцией IniReadSection()
Код:
#include <Array.au3>

$aReadSect = IniReadSection("Dnetr28.txt", "D-Link.NTx86.6.1")
_ArrayDisplay($aReadSect)
 

VVV

Новичок
Сообщения
2
Репутация
0
да, стандартной возвращается нормально, но мне нужна эта функция
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
VVV [?]
при использовании функции указанной в ответе 3, почему-то не возвращается секция D-Link.NTx86.6.1 из ini файла
Потому что у секции на окончании есть лишние пробелы, их видимо нужно игнорировать (а также и возможные комментарии).
Поправил.
 
Верх