Подразделы (SubSections) в INI-файле
Модератор: Модераторы
Подразделы (SubSections) в INI-файле
В официальной спецификации INI-файлов заложена возможность использования подразделов, а в дельфи вообще есть процедура ReadSubSections . Понятное дело, что для более-менее сложных случаев лучше использовать XSL/ XML и DOM но если задача укладывается в рамки простого и главное в принципе редактируемого в ручном режиме INI-файла то "нафига козе боян"?
В общем народ, кто-нибудь сталкивался с готовым решением для работы с SubSections INI-файлов в Lazarus/fpc ?
(ничего сложного в этом нет, но очень не хочется "изобретать велосипед" )
В общем народ, кто-нибудь сталкивался с готовым решением для работы с SubSections INI-файлов в Lazarus/fpc ?
(ничего сложного в этом нет, но очень не хочется "изобретать велосипед" )
https://stackoverflow.com/questions/210 ... -ini-files
вот описание как это сделать
только подсекция для ini это притянутая за уши технология, ибо формат ini не предусматривает работу с подсекциям в принципе.
вот описание как это сделать
только подсекция для ini это притянутая за уши технология, ибо формат ini не предусматривает работу с подсекциям в принципе.
Спасибо за отзыв ...
https://en.wikipedia.org/wiki/INI_file
Можно сделать проще ...
Если Раздел то переключить текущий INI-файл ( и возврат по аналогии с каталогом-фс то бишь <..> )
Но как-то это громоздко ( куча INI-файлов)
Но это в дельфи в лазарусе метода ReadSubSections нет.ssnakess писал(а):вот описание как это сделать
В принципе согласен но ..ssnakess писал(а):только подсекция для ini это притянутая за уши технология,
https://en.wikipedia.org/wiki/INI_file
Добавлено спустя 18 минут 19 секунд:В некоторых случаях также поддерживается относительная вложенность, когда начальная точка выражает вложенность в предыдущий раздел:[11]
[раздел]
домен = example.com
[.подраздел]
foo = bar
Исторически также существовали способы выражения вложенности, альтернативные точке (например, файл драйвера IBM для Microsoft Windows devlist.ini, в котором обратная косая черта использовалась в качестве разделителя вложенности в форме [A/B/C]; или AEMANAGR.INI файл Microsoft Visual Studio, в котором использовался совершенно другой синтаксис в форме [A] и B,C,P = V). Некоторые анализаторы вообще не предлагали поддержки вложенности и не учитывали иерархию, но вложенность все равно можно было частично эмулировать, используя тот факт, что [A.B.C] представляет собой уникальный идентификатор.
Можно сделать проще ...
Если Раздел то переключить текущий INI-файл ( и возврат по аналогии с каталогом-фс то бишь <..> )
Но как-то это громоздко ( куча INI-файлов)
[{C382B407-CFF4-4D4A-9B85-49A276F70EA0}]
ID={C382B407-CFF4-4D4A-9B85-49A276F70EA0}
TYPE_NODE=tnFolderServers
CAPTION=f2
LIST_OF_CHILDRENS={BA5F7984-3657-47A8-BF8D-E93CF08BFA03},
[{BA5F7984-3657-47A8-BF8D-E93CF08BFA03}]
ID={BA5F7984-3657-47A8-BF8D-E93CF08BFA03}
TYPE_NODE=tnServer
CAPTION=s1
LIST_OF_CHILDRENS={1D4B1A84-2195-4A33-AF3F-0652F58E0EE1},{9F4D9467-6C6B-4320-A56B-499821A60082}
ID={C382B407-CFF4-4D4A-9B85-49A276F70EA0}
TYPE_NODE=tnFolderServers
CAPTION=f2
LIST_OF_CHILDRENS={BA5F7984-3657-47A8-BF8D-E93CF08BFA03},
[{BA5F7984-3657-47A8-BF8D-E93CF08BFA03}]
ID={BA5F7984-3657-47A8-BF8D-E93CF08BFA03}
TYPE_NODE=tnServer
CAPTION=s1
LIST_OF_CHILDRENS={1D4B1A84-2195-4A33-AF3F-0652F58E0EE1},{9F4D9467-6C6B-4320-A56B-499821A60082}
Интересно, но не очень понятно... Например зачем нужен ключ "ID={...}" и главное чем и как это читается создается и поддерживается .В смысле если это запись некого "дерева нод" то где можно посмотреть код который это делает ?
(Написать что-то свое проблемы нет, но это как раз и будет "изобретение велосипеда" )
Ладно похоже готового решения нет!
Зы
Нашел только вот такую древнюю кривулю, но примеров использования нет и вообще хотя я и добился "условной собираемости" (пока что довольно халтурно) в относительно современном лазарусе но "мучают меня смутные сомнения" (например UTF8 автор явно не использовал ) и вообще непонятно есть ли там поддержка SubSections или нет (хотя ясно что если нет то ее точно проще добавить чем в стандартный TIniFile )
(Написать что-то свое проблемы нет, но это как раз и будет "изобретение велосипеда" )
Ладно похоже готового решения нет!
Зы
Нашел только вот такую древнюю кривулю, но примеров использования нет и вообще хотя я и добился "условной собираемости" (пока что довольно халтурно) в относительно современном лазарусе но "мучают меня смутные сомнения" (например UTF8 автор явно не использовал ) и вообще непонятно есть ли там поддержка SubSections или нет (хотя ясно что если нет то ее точно проще добавить чем в стандартный TIniFile )
Код: Выделить всё
Unit RialIniFile;
Interface
Uses
{RialObject,} Classes;
Type
TSection = record
Name : String;
HName : String;
Idents : TStringList;
end;
ptSection = ^TSection;
TRialIniFile = Class //(TRialObject)
protected
FSections : TList;
FSorted : Boolean;
FLeftSym : Char;
FRightSym : Char;
FDelim : Char;
//Уничтожение веток
procedure DestroyIdents;
//Установка режима сортировки
procedure SetSorted(Const Sorted : Boolean);
//Установка разделителя
procedure SetDelim(Const Delim : Char);
//Создание секции
function AddSection(Const SectionName : String) : ptSection;
//Сортировка веток
procedure SortIdents;
//Поиск секции
function FindExistsSection(Const SectionName : String) : ptSection;
//Сортировка заголовка
procedure SortSections;
//Поиск секции с возможностью создания
function FindSection(Const SectionName : String) : ptSection;
//Добавление значения
procedure AddIdentValue(Const Section, Ident, Value : String);
//Получение значения
function GetIdentValue(Const Section, Ident, DefaultValue : String) : String;
//Количество секций
function GetSectionsCount : Integer;
//Получение секции
function GetSections(Const Index : Integer) : TStringList;
//Получение имена секции
function GetSectionName(Const Index : Integer) : String;
//Установка имена секции
procedure SetSectionName(Const Index : Integer; Const SectionName : String);
protected
//получить реальный размер
// function _GetSize : Cardinal; override;
public
constructor Create;
destructor Destroy; override;
procedure WriteString (Const Section, Ident : String; Const Value : String);
procedure WriteInteger(Const Section, Ident : String; Const Value : Int64);
procedure WriteFloat (Const Section, Ident : String; Const Value : Extended);
procedure WriteBool (Const Section, Ident : String; Const Value : Boolean);
function ReadString (Const Section, Ident : String; Const Default : String = '' ) : String;
function ReadInteger(Const Section, Ident : String; Const Default : Int64 = 0 ) : Int64;
function ReadFloat (Const Section, Ident : String; Const Default : Extended = 0.0 ) : Extended;
function ReadBool (Const Section, Ident : String; Const Default : Boolean = False) : Boolean;
//Перевод строки в верхний регистр
// function UpperCase(Const S : String) : String;
//Логичекий тип - строка
function BoolToStr(Const B : Boolean) : String;
//Строка - лгический тип
function StrToBool(Const S : String) : Boolean;
//Очистка
procedure Clear;
//Сортировка
procedure Sort;
//Поиск идентификатора
function FindIdent(Const PrevSection, Ident : String; Out Section, Value : String) : Boolean;
//Индекс секции
function IndexOfSection(Const SectionName : String) : Integer;
//Чтение строк секции
function ReadSection(Const SectionName : String; Const StringList : TStringList) : Boolean;
//Запись строк в секцию
procedure WriteSection(Const SectionName : String; Const StringList : TStringList);
//Созранение в список
procedure SaveToStringList(Const StringList : TStringList);
//Сохранение в файл
function SaveToFile(Const FileName : String) : Boolean;
//Загрузка из списка
procedure LoadFromStringList(Const StringList : TStringList);
//Загрузка из файла
function LoadFromFile(Const FileName : String) : Boolean;
//Флаг сортировки
property Sorted : Boolean read FSorted write SetSorted;
//Левый разделитель
property LeftSym : Char read FLeftSym write FLeftSym;
//Правый разделитель
property RightSym : Char read FRightSym write FRightSym;
//Разделитель значения
property Delim : Char read FDelim write SetDelim;
//Количество секций
property SectionCount : Integer read GetSectionsCount;
//Списки секций
property Sections[Const Index : Integer] : TStringList read GetSections;
//Имена секций
property SectionNames[Const Index : Integer] : String
read GetSectionName write SetSectionName;
end;
Implementation
Uses
SysUtils;
Const
VoidName = '';
VoidInt = -1;
{
function TRialIniFile.UpperCase(Const S : String) : String;
Var
Ch : Char;
L : Integer;
Source : PChar;
Dest : PChar;
begin
{L :=Length(S);
SetLength(Result, L);
Source :=Pointer(S);
Dest :=Pointer(Result);
While (L <> 0) do begin
Ch :=Source^;
Case Ch of
'a'..'z' : Dec(Ch, 32);
'а'..'я' : Dec(Ch, 32);
'ё' : Ch :='Ё';
end;
Dest^ :=Ch;
Inc(Source);
Inc(Dest);
Dec(L);
end;
end;
}
function TRialIniFile.BoolToStr(Const B : Boolean) : String;
begin
If (B)then Result :='1'
else Result :='0';
end;
function TRialIniFile.StrToBool(Const S : String) : Boolean;
Var
N : Integer;
E : Integer;
begin
Val(S, N, E);
Result :=(E = 0)and(N > 0);
end;
constructor TRialIniFile.Create;
begin
//родительский метод
Inherited Create;
FSections :=TList.Create;
FSorted :=False;
FLeftSym :='[';
FRightSym :=']';
FDelim :='=';
end;
destructor TRialIniFile.Destroy;
begin
//Уничтожение веток
DestroyIdents;
//Уничтожение заголовка
FSections.Free;
//Внутренний вызов
inherited Destroy;
end;
{function TRialIniFile._GetSize : Cardinal;
Var
I : Integer;
begin
Result := (Inherited _GetSize);
For I :=0 to FSections.Count - 1 do
With ptSection(FSections.Items[I])^ do begin
Inc(Result, SizeOf(TSection));
Inc(Result, Length(Name));
Inc(Result, Length(HName));
Inc(Result, Length(Idents.Text));
end;
end;
}
procedure TRialIniFile.DestroyIdents;
Var
I : Integer;
begin
For I :=0 to FSections.Count - 1 do
ptSection(FSections.Items[I])^.Idents.Free;
end;
procedure TRialIniFile.Clear;
begin
//Инучтожение всех веток
DestroyIdents;
//Очистка ссылок
FSections.Clear;
end;
function TRialIniFile.AddSection(Const SectionName : String) : ptSection;
begin
New(Result);
With Result^ do begin
Name :=SectionName;
HName :=UpperCase(Name);
Idents :=TStringList.Create;
end;
FSections.Add(Result);
If (FSorted)then
SortSections;
end;
function TRialIniFile.FindExistsSection(Const SectionName : String) : ptSection;
Var
I : Integer;
N : Integer;
HSectionName : String;
begin
Result :=Nil;
N :=FSections.Count;
If (N > 0)then begin
HSectionName :=UpperCase(SectionName);
For I :=0 to N - 1 do
If (ptSection(FSections.Items[I])^.HName = HSectionName)then begin
Result :=FSections.Items[I];
Exit;
end;
end;
end;
procedure TRialIniFile.SetSorted(Const Sorted : Boolean);
Var
I : Integer;
begin
For I :=0 to FSections.Count - 1 do
ptSection(FSections.Items[I])^.Idents.Sorted :=Sorted;
If(Sorted = True)and(FSorted = False)then SortSections;
FSorted :=Sorted;
end;
procedure TRialIniFile.SortIdents;
Var
I : Integer;
begin
For I :=0 to FSections.Count - 1 do
ptSection(FSections.Items[I])^.Idents.Sort;
end;
procedure TRialIniFile.Sort;
begin
SortIdents;
SortSections;
end;
function RialConfigCompare(Item1, Item2 : Pointer) : Integer;
Var
ptS1 : ptSection;
ptS2 : ptSection;
begin
ptS1 :=Item1;
ptS2 :=Item2;
If (ptS1^.HName > ptS2^.HName)then Result :=VoidInt
else
If (ptS1^.HName < ptS2^.HName)then Result :=1
else Result :=0;
end;
procedure TRialIniFile.SortSections;
begin
FSections.Sort(RialConfigCompare);
end;
function TRialIniFile.FindSection(Const SectionName : String) : ptSection;
begin
Result :=FindExistsSection(SectionName);
If (Result = Nil)then
Result :=AddSection(SectionName);
end;
procedure TRialIniFile.AddIdentValue(Const Section, Ident, Value : String);
Var
ptS : ptSection;
begin
ptS :=FindSection(Section);
ptS^.Idents.Values[Ident] :=Value;
end;
procedure TRialIniFile.SaveToStringList(Const StringList : TStringList);
Var
I : Integer;
J : Integer;
N : Integer;
ptS : ptSection;
begin
N :=FSections.Count;
If (N > 0)then begin
//Запись комметария
ptS :=FindExistsSection(VoidName);
If(ptS <> Nil)and(ptS^.Idents.Count > 0)then
With ptS^.Idents do
For J :=0 to Count - 1 do
StringList.Add(Strings[J]);
//Прочие ветки
For I :=0 to N - 1 do begin
ptS :=FSections.Items[I];
If (ptS^.Idents.Count>0)and(ptS^.Name <> VoidName)then begin
StringList.Add(FLeftSym + ptS^.Name + FRightSym);
With ptS^.Idents do
For J :=0 to Count - 1 do
StringList.Add(Strings[J]);
end; //If
end; //For
end; //If N>0
end;
function TRialIniFile.SaveToFile(Const FileName : String) : Boolean;
Var
SL : TStringList;
begin
Result :=False;
SL :=TStringList.Create;
Try
SaveToStringList(SL);
Try
SL.SaveToFile(FileName);
Except
Exit;
end;
Finally
SL.Free;
end;
Result :=True;
end;
function TRialIniFile.GetIdentValue(Const Section, Ident, DefaultValue : String) : String;
Var
ptS : ptSection;
begin
ptS :=FindExistsSection(Section);
If (ptS <> Nil)then begin
Result :=ptS^.Idents.Values[Ident];
If (Result = VoidName)then
Result :=DefaultValue;
end else
Result :=DefaultValue;
end;
procedure TRialIniFile.SetDelim(Const Delim : Char);
Var
I : Integer;
begin
FDelim :=Delim;
For I :=0 to FSections.Count - 1 do
ptSection(FSections.Items[I])^.Idents.Delimiter :=Delim;
end;
procedure TRialIniFile.LoadFromStringList(Const StringList : TStringList);
Var
I : Integer;
Len : Integer;
Line : String;
ptCurrentSection : ptSection;
begin
ptCurrentSection :=FindSection(VoidName); //В начале возможен комментарий
For I :=0 to StringList.Count - 1 do begin
Line :=StringList.Strings[I];
Len :=Length(Line);
If (Len>0)then
If (Line[1] = FLeftSym)and(Line[Len] = FRightSym)then ptCurrentSection :=FindSection(Copy(Line, 2, Len - 2))
else ptCurrentSection.Idents.Add(Line);
end;
end;
function TRialIniFile.LoadFromFile(Const FileName : String) : Boolean;
Var
SL : TStringList;
begin
Result :=False;
If (FileExists(FileName))then begin
SL :=TStringList.Create;
Try
Try
SL.LoadFromFile(FileName);
Except
Exit;
end;
LoadFromStringList(SL);
Finally
SL.Free;
end;
Result :=True;
end;
end;
function TRialIniFile.ReadSection(Const SectionName : String; Const StringList : TStringList) : Boolean;
Var
ptS : ptSection;
begin
ptS :=FindExistsSection(SectionName);
If (ptS <> Nil)then begin
StringList.Assign(ptS^.Idents);
Result :=True;
end else
Result :=False;
end;
procedure TRialIniFile.WriteSection(Const SectionName : String; Const StringList : TStringList);
Var
ptS : ptSection;
I : Integer;
begin
ptS :=FindSection(SectionName);
For I :=0 to StringList.Count - 1 do
ptS^.Idents.Add(StringList.Strings[I]);
end;
procedure TRialIniFile.WriteString(Const Section, Ident : String; Const Value : String);
begin
AddIdentValue(Section, Ident, Value);
end;
procedure TRialIniFile.WriteInteger(Const Section, Ident : String; Const Value : Int64);
begin
AddIdentValue(Section, Ident, IntToStr(Value));
end;
procedure TRialIniFile.WriteFloat(Const Section, Ident : String; Const Value : Extended);
begin
AddIdentValue(Section, Ident, FloatToStr(Value));
end;
procedure TRialIniFile.WriteBool(Const Section, Ident : String; Const Value : Boolean);
begin
AddIdentValue(Section, Ident, BoolToStr(Value));
end;
function TRialIniFile.ReadString(Const Section, Ident : String; Const Default : String) : String;
begin
Result :=GetIdentValue(Section, Ident, Default);
end;
function TRialIniFile.ReadInteger(Const Section, Ident : String; Const Default : Int64) : Int64;
begin
Result :=StrToInt64(GetIdentValue(Section, Ident, IntToStr(Default)));
end;
function TRialIniFile.ReadFloat(Const Section, Ident : String; Const Default : Extended) : Extended;
begin
Result :=StrToFloat(GetIdentValue(Section, Ident, FloatToStr(Default)));
end;
function TRialIniFile.ReadBool(Const Section, Ident : String; Const Default : Boolean) : Boolean;
begin
Result :=StrToBool(GetIdentValue(Section, Ident, BoolToStr(Default)));
end;
function TRialIniFile.FindIdent(Const PrevSection, Ident : String; Out Section, Value : String) : Boolean;
Var
ptS : ptSection;
I : Integer;
P : Integer;
S : String;
begin
ptS :=FindExistsSection(PrevSection);
If (ptS = Nil)then P :=0
else P :=FSections.IndexOf(ptS) + 1;
Result :=False;
For I:=P to FSections.Count - 1 do begin
ptS :=FSections.Items[I];
S :=ptS^.Idents.Values[Ident];
If (S <> VoidName)then begin
Section :=ptS^.Name;
Value :=S;
Result :=True;
Exit;
end;
end;
end;
function TRialIniFile.GetSectionsCount : Integer;
begin
Result :=FSections.Count;
end;
function TRialIniFile.GetSections(Const Index : Integer) : TStringList;
begin
Result :=ptSection(FSections.Items[Index])^.Idents;
end;
procedure TRialIniFile.SetSectionName(Const Index : Integer; Const SectionName : String);
begin
With ptSection(FSections.Items[Index])^ do begin
Name :=SectionName;
HName :=UpperCase(SectionName);
end;
end;
function TRialIniFile.GetSectionName(Const Index : Integer) : String;
begin
With ptSection(FSections.Items[Index])^ do begin
Result :=Name;
//HName :=UpperCase(SectionName);
end;
end;
function TRialIniFile.IndexOfSection(Const SectionName : String) : Integer;
Var
ptS : ptSection;
begin
ptS :=FindExistsSection(SectionName);
If (ptS = Nil)then Result :=VoidInt
else Result :=FSections.IndexOf(ptS) + 1;
end;
end.
(*
{
Поиск идентификатора:
Var
sSec : String;
sOldSec : String;
sVal : String;
...
sldSec :="";
sVal :="";
While(FindIdent(sOldSec, "Имя поля", sSec, sVal))do begin
ShowMessage(sVal);
sOldsec :=sSec;
end;
Версия 2.2.0
}
*)
Редактируемый в ручном режиме ini-файл - это текстовый файл.Alex2013 писал(а): ... если задача укладывается в рамки простого и главное в принципе редактируемого в ручном режиме INI-файла то "нафига козе боян"? ...
Никто никогда не будет вам писать то, что вам нужно. Ваш файл нужен только вам.Alex2013 писал(а): ... В общем народ, кто-нибудь сталкивался с готовым решением для работы с SubSections INI-файлов в Lazarus/fpc? ...
Работа с текстовым файлом уже изобретена. В поисках готового решения вы и прикрутите кучу косяков в виде многоколесного драндулета (гвоздями прибъете свое творение к версии и виду ОС, версии компилятора, наличия вспомогательных системных, в том числе, библиотек), вместо простого и ясного, оптимизмрованного под вашу задачу, изящного решения. В поисках борьбы с чужими косяками нет ограничений.Alex2013 писал(а): ... (ничего сложного в этом нет, но очень не хочется "изобретать велосипед" )
ИМХО, если нужна древовидная структура файла с настройками, то лучше и проще использовать или XML или JSON
Тем более что это уже все реализовано из коробки. И вы получите и кросплатформенность компиляции, и удобство для внутреннего использования.
Т.к. прикручивая подразделы к ini Вы заранее закладываете логику работы с ними, понятную только вам, и которую потом будет сложно объяснить потребителю.
Тогда как XML или JSON - понятны и описаны
Тем более что это уже все реализовано из коробки. И вы получите и кросплатформенность компиляции, и удобство для внутреннего использования.
Т.к. прикручивая подразделы к ini Вы заранее закладываете логику работы с ними, понятную только вам, и которую потом будет сложно объяснить потребителю.
Тогда как XML или JSON - понятны и описаны
Это кусок реального ини файла. Главное - это строка:Alex2013 писал(а):Например зачем нужен ключ "ID={...}" и главное чем и как это читается создается и поддерживается .
LIST_OF_CHILDRENS={1D4B1A84-2195-4A33-AF3F-0652F58E0EE1},{9F4D9467-6C6B-4320-A56B-499821A60082}
Т.е. список секций, которые являются ветками узла. Реализация простая. Каждый узел пишет себя в ини файл сам и вызывает метод записи у детей.
Я в курсе... ( Именно так я поступил при переименовании и "перестановке" секций - в первом случае просто отредактировал текст, во втором "пересобрал" INI в памяти, перечитав секции в нужном порядке )RRYTY писал(а): Работа с текстовым файлом уже изобретена. В поисках готового решения вы и прикрутите кучу косяков в виде многоколесного драндулета (гвоздями прибъете свое творение к версии и виду ОС, версии компилятора, наличия вспомогательных системных, в том числе, библиотек), вместо простого и ясного, оптимизмрованного под вашу задачу, изящного решения. В поисках борьбы с чужими косяками нет ограничений.
Но увидев, что в дельфи есть метод ReadSubSections я подумал, что возможно где-то есть его готовый "самописный аналог" для лазарус.
Зы
Спасибо за отзывы и советы! Пока делаю через " переключение текущего ini-файла" (это точно надежнее всех прочих вариантов ) а дальше возможно сделаю "вложенные секции" замаскированные под комментарий. ( Идея проста: читаю "секцию подраздела" через ReadRawSection убираю комментарий и загружаю в TMemIniFile ( "наглядная бесконечная вложенность секций" прилагается автоматом )
Код: Выделить всё
[Секция1]
...
[Секция2]
...
[СубСекция1]
# [Секция1]
# ...
# [Секция2]
# ...
# [СубСекция 1_1 ]
# # [Секция1]
# # ...
# # [Секция2]
# # ...
Код: Выделить всё
ini.WriteString('Section1/SubSection0', 'IdentX', 'ValueX');Сделал с "переключением ини-файла".

Добавлено спустя 1 час 5 минут 14 секунд:

Добавлено спустя 1 час 5 минут 14 секунд:
Это понятно но выйдет громоздко и почти "нечитаемо", а пожалуй единственное достоинство Ини-файлов именно в том что они поддерживают "ручной режим" правки и просмотра.v-t-l писал(а):Код: Выделить всё
ini.WriteString('Section1/SubSection0', 'IdentX', 'ValueX');
возможно так?!Alex2013 писал(а):Сделал с "переключением ини-файла".
Код: Выделить всё
[sec1]
...
[sec2]
...
[sec2_sub1]
...
[sec2_sub2]
...
[sec2_sub3]
...
Так разумеется проще но все равно громоздко . ( нет "дерева" разделов ) так что я все-же сделал в виде ссылки на отдельный ини-файл + специальная запись с ссылкой на предыдущий раздел ( если это не корневая запись ). Разумеется можно сделать некий гибрид с расширенным синтаксисом но тогда проще использовать DOM+XML и т.п. А тут основная идея сделать SubSections штатно ( используя относительно стандартный формат INI-файла ) и более менее наглядно.
-
xchgeaxeax
- постоялец
- Сообщения: 207
- Зарегистрирован: 11.05.2023 02:51:40
По моему вы изобретаете велосипед. REG файлы это INI с секциями. А на строение конечного дерева можете посмотреть в REGEDIT.
Это разумеется интересная мысль но парсеры REG обычно работают с реестром и не умеют читать REG файлы "в режиме INI" ( записать REG-файлы многие парсеры могут и "в режиме INI" а читать без записи в реестр не умеют бо "нафига козе боян"xchgeaxeax писал(а):По моему вы изобретаете велосипед. REG файлы это INI с секциями. А на строение конечного дерева можете посмотреть в REGEDIT.
