Top Edit
Теперь я понял, что вы более привыкли к Java, и это объясняет вашу проблему.Java использует сборщик мусора: если у вас есть ссылка на что-то, то одна вещь действительная .Delphi не использует GC, вы отвечаете за освобождение всей выделенной памяти.Это приводит ко второй проблеме: вы можете освободить память, на которую ссылаетесь, ничто не мешает вам сделать это.В своей процедуре parsetestfile
вы добавляете subsplit2
в словарь, поэтому сохраняете копию этой ссылки.Позже в той же процедуре вы освобождаете subsplit2
, поэтому ваш словарь теперь содержит ссылку на то, что Delphi считает «свободной памятью»!
С Delphi вам нужно быть очень осторожным и обдумывать жизненный циклуправление.В этом случае вы, очевидно, не можете освободить subsplit2
в самой процедуре parsetestfile
, но вам нужно освободить его позже.Вам нужно будет освободить его, когда вы освободите Dict
, посмотрите мой первоначальный код, чтобы узнать, как это сделать.
* Рекомендовано
Вот ваш код с множеством вещейфиксированный.Пожалуйста, прочитайте комментарии, я вставлял комментарии везде, где я что-то изменил.
Он компилируется и значения выдерживают процедуру разбора, но я не уверен, чего вы хотите достичь, и вы забыли предоставить образец текстового файла: Iпришлось "сделать один".
program Project23;
{$APPTYPE CONSOLE}
uses
SysUtils, Classes, StrUtils, Dialogs, Generics.collections;
var deviceid, key, topmodule : string;
dict: TDictionary<String, TStringlist>;
KeysList: TStringList;
KeyName: string;
i: integer;
function DeleteSpaces(str: string): string;
var
i: Integer;
begin
i:=0;
while i<=Length(str) do
if str[i]=' ' then Delete(str, i, 1)
else Inc(i);
Result:=str;
end;
procedure HandleOneKey(KeyIndex:Integer; PrevKeys:string);
var L:TStringList;
i:Integer;
Part: string;
KeyName: string;
begin
KeyName := KeysList[KeyIndex];
L := dict[KeyName];
for i:=0 to L.Count-1 do
begin
writeln(L[i]);
Part := KeyName + '=' + L[i];
if KeyIndex = (KeysList.Count-1) then
WriteLn(PrevKeys + ' ' + Part)
else
HandleOneKey(KeyIndex+1, PrevKeys + ' ' + Part);
end;
end;
procedure Split(const Delimiter: Char;Input: string;const Strings: TStrings);
begin
Strings.Clear;
Strings.Delimiter := Delimiter;
Strings.DelimitedText := Input;
end;
procedure parsetestfile;
var testfile: Textfile;
text: string;
splitarray: TStringList;
subsplit1, subsplit2: TStringList;
ValueName:TStringList; // Never Ever ignore compiler warnings!
i: Integer; // Never Ever ignore compiler warnings!
begin
splitarray := TStringList.Create;
subsplit1:= TStringList.Create;
AssignFile(testfile, 'c:\temp\testfile.txt') ;
Reset(testfile);
while not Eof(testfile) do
begin
ReadLn(testfile, text);
if AnsiContainsStr(text, '=') then
begin
Split('=', text, splitarray);
splitarray[0] := trim(splitarray[0]);
splitarray[1] := DeleteSpaces(splitarray[1]);
if AnsiStartsStr('data', splitarray[0]) then
begin
subsplit2:= TStringList.Create; // Moved the creation of subsplit2 over here, because you need one fresh list for every line of text you read.
split(' ', splitarray[0], subsplit1); // can't split on SPACE because the previous split allready broke the text at "=" and at SPACE. That's how DelimitedText works!
// splitarray[0]:=subsplit1[1]; // splitarray[0] already contains the stuff before "="; And you should check the nubmer of lines in subsplit1!
split(',', splitarray[1], subsplit2);
dict.Add(splitarray[0], subsplit2);
for ValueName in dict.Values do
begin
for i := 0 to Valuename.Count - 1 do
writeLN('Values are : '+ Valuename[i]); // Only use Write when you intend to write the line terminator later
writeln;
end;//for
end;//end-data-check
end;//end-=-check
end;//while
CloseFile(testfile);
splitarray.Free;
subsplit1.Free;
// subsplit2.Free; // Ooops! You're freeing Subsplit2, after you added it as a value in the dict.
end;
begin
dict := TDictionary<String, TStringlist>.Create;
parsetestfile;
KeysList := TStringList.Create;
for KeyName in dict.Keys do
KeysList.Add(KeyName);
for i := 0 to Keyslist.Count - 1 do
begin
writeln('Keylist Items: ' + Keyslist[i]);
end;
if KeysList.Count > 0 then
begin
HandleOneKey(0, '');
end;
dict.Free; // dict.Destroy; // never call "Destroy" directly, call .Free.
Keyslist.Free;
WriteLn('Press ENTER to make the window go away');
ReadLn;
end.