Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 28.01.2018, 22:10
Taras2020 Taras2020 вне форума
Прохожий
 
Регистрация: 15.01.2018
Сообщения: 36
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию Утечка памяти out of memory

Добрый день, уважаемые пользователи.
Суть проблемы: При запуске процедуры идет работа в файле размеров в .... мегабайт. И после 5 секунд выскакивает окно out of memory. Хотя файлы до 200 мегабайт нормально.

Я так понял что это из за недостатка выделенной памяти на массив, строку. Какие ошибки допущены в коде и как решить эту проблему?
Код:
procedure Tfrm_Main.Run;
var afList: TStringDynArray;
    i, j, k: integer;
    L, rL, fL: TStringList;
    NewName, tmp: String;

begin
 memo_Log.Lines.Add(Format('Начало обработки: %s', [DateTimeToStr(Now)]));
 memo_Log.Lines.Add('///');
 memo_Log.Lines.Add('');
 L := TStringList.Create;
 for i := 0 to memo_Folders.Lines.Count - 1 do
  
begin
   afList := TDirectory.GetFiles(memo_Folders.Lines[i], '*.txt', SO);
   for j := 0 to Length(afList) - 1 do
    L.Add(afList[j]);
  end;
 rL := TStringList.Create;
 rL.Text := Trim(memo_List.Text);
 k := 0;
 fL := TStringList.Create;
 for i := 0 to L.Count - 1 do
  
begin
   memo_Log.Lines.Add(Format('Обработка файлов %s', [L.Strings[i]]));
   fL.LoadFromFile(L.Strings[i]);
   tmp := ExtractFileName(L.Strings[i]);
   tmp := Copy(tmp, 1, Pos('.', tmp) - 1);
   NewName := Format('%s%s.%s', [ExtractFilePath(L.Strings[i]),
                                     tmp,
                                     FormatDateTime('ddmmyy_hhnn', Now)]);
   
if rg_Order.ItemIndex = 1 then
    for j := 0 to rL.Count - 1 do
     rL.Exchange(j, RandomRange(0, rL.Count));
   for j := 0 to fL.Count - 1 do
    begin
     fL.Strings[j] := StringReplace(fL.Strings[j], edt_Word.Text, rL.Strings[k], RF);
     inc(k);
     if k = rL.Count then k := 0;
    end;
   fL.SaveToFile(NewName);
   memo_Log.Lines.Add(Format('Сохранение под именем %s', [NewName]));
   memo_Log.Lines.Add('');
  end;
 memo_Log.Lines.Add('///');
 memo_Log.Lines.Add(Format('Окончание обработки: %s', [DateTimeToStr(Now)]));
 fL.Free;
 rL.Free;
 L.Free;
 btn_Next.Enabled := false;
 LoadBMP(btn_Prev, 5);
 btn_Prev.Caption := 'С начала';
end;

Последний раз редактировалось Taras2020, 31.01.2018 в 12:48.
Ответить с цитированием
  #2  
Старый 30.01.2018, 07:14
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,056
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Ну, убивать, в смысле руки отрывать, за такое надо.
Ты же все-равно делаешь замену в рамках одной строки. Ну так нафига читать файл целиком? Читай по одной строке. Что-то типа:
Код:
procedure ReplaceSubStringInFile(ASrcFileName, ATgtFileName, ASrcStr, ATgtStr : String);
var
  F_Src, F_Tgt : TextFile;
  S : String;
begin
  AssignFile(F_Src,ASrcFileName);
  AssingFile(F_Tgt,ATgtFileName);
  Reset(F_Src);
  Reqwrite(F_Tgt);
  While Not EOF(F_Src) Do
    Begin
      ReadLN(F_Src,S);
      S := StringReplace(S,ASrcStr,ATgtStr,[srReplaceAll]);
      WriteLn(F_Tgt,S);
    End;
  CloseFile(F_Src);
  CloseFile(F_Tgt);
end;
Ответить с цитированием
Этот пользователь сказал Спасибо lmikle за это полезное сообщение:
Taras2020 (30.01.2018)
  #3  
Старый 30.01.2018, 12:24
Taras2020 Taras2020 вне форума
Прохожий
 
Регистрация: 15.01.2018
Сообщения: 36
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
Ну, убивать, в смысле руки отрывать, за такое надо.
Ты же все-равно делаешь замену в рамках одной строки. Ну так нафига читать файл целиком? Читай по одной строке. Что-то типа:
К сожалению я делаю замену не в рамках одной строки а во всех строках. Про ReplaceSubStringInFile знаю, но решение пока что не нашел. Может еще есть варианты ?
Ответить с цитированием
  #4  
Старый 30.01.2018, 14:00
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Цитата:
Сообщение от Taras2020
К сожалению я делаю замену не в рамках одной строки а во всех строках. Про ReplaceSubStringInFile знаю, но решение пока что не нашел. Может еще есть варианты ?
Тебе говорят, что замену ты выполняешь только в пределах строки....КАЖДОЙ строки файла. Т.е. построчно. Тебе и предлагают, не вываливать (полная загрузка в TStrings) всю кашу файла в память, а обрабатываеть его считывая ПОСТРОЧНО.
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.
Ответить с цитированием
Этот пользователь сказал Спасибо dr. F.I.N. за это полезное сообщение:
Taras2020 (31.01.2018)
  #5  
Старый 31.01.2018, 11:16
Taras2020 Taras2020 вне форума
Прохожий
 
Регистрация: 15.01.2018
Сообщения: 36
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от dr. F.I.N.
Тебе говорят, что замену ты выполняешь только в пределах строки....КАЖДОЙ строки файла. Т.е. построчно. Тебе и предлагают, не вываливать (полная загрузка в TStrings) всю кашу файла в память, а обрабатываеть его считывая ПОСТРОЧНО.
A какой алгоритм считывая построчно выходя из моего кода. Подскажите пожалуйста ?
Ответить с цитированием
  #6  
Старый 31.01.2018, 11:41
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Не стал разбираться досконально с кодом, но что-то такое должно получится. Imikle все и так написал.

Код:
procedure Tfrm_Main.Run;
var afList: TStringDynArray;
    i, j, k: integer;
    L, rL{, fL}: TStringList;
    NewName, tmp: String;
//====
F_Src, F_Tgt : TextFile;
  S : String;
begin
 memo_Log.Lines.Add(Format('Начало обработки: %s', [DateTimeToStr(Now)]));
 memo_Log.Lines.Add('///');
 memo_Log.Lines.Add('');
 L := TStringList.Create;
 for i := 0 to memo_Folders.Lines.Count - 1 do
  
begin
   afList := TDirectory.GetFiles(memo_Folders.Lines[i], '*.txt', SO);
   for j := 0 to Length(afList) - 1 do
    L.Add(afList[j]);
  end;
 rL := TStringList.Create;
 rL.Text := Trim(memo_List.Text);
 k := 0;
 //fL := TStringList.Create;
 for i := 0 to L.Count - 1 do
  
begin
   memo_Log.Lines.Add(Format('Обработка файлов %s', [L.Strings[i]]));
   //fL.LoadFromFile(L.Strings[i]);
   AssignFile(F_Src,L.Strings[i]);
  Reset(F_Src);
   tmp := ExtractFileName(L.Strings[i]);
   tmp := Copy(tmp, 1, Pos('.', tmp) - 1);
   NewName := Format('%s%s.%s', [ExtractFilePath(L.Strings[i]),
                                     tmp,
                                     FormatDateTime('ddmmyy_hhnn', Now)]);

  AssingFile(F_Tgt,NewName);
  Rewrite(F_Tgt);

if rg_Order.ItemIndex = 1 then
    for j := 0 to rL.Count - 1 do
     rL.Exchange(j, RandomRange(0, rL.Count));

While Not EOF(F_Src) Do
    Begin
      ReadLN(F_Src,S);
      S := StringReplace(S, edt_Word.Text, rL.Strings[k], RF);
      WriteLn(F_Tgt,S);
inc(k);
     if k = rL.Count then k := 0;
    End;
  // for j := 0 to fL.Count - 1 do
    //begin
     //fL.Strings[j] := StringReplace(fL.Strings[j], edt_Word.Text, rL.Strings[k], RF);
     //inc(k);
     //if k = rL.Count then k := 0;
    //end;
   //fL.SaveToFile(NewName);
  CloseFile(F_Src);
  CloseFile(F_Tgt);
   memo_Log.Lines.Add(Format('Сохранение под именем %s', [NewName]));
   memo_Log.Lines.Add('');
  end;
 memo_Log.Lines.Add('///');
 memo_Log.Lines.Add(Format('Окончание обработки: %s', [DateTimeToStr(Now)]));
 //fL.Free;
 rL.Free;
 L.Free;
 btn_Next.Enabled := false;
 LoadBMP(btn_Prev, 5);
 btn_Prev.Caption := 'С начала';
end;

Кстати, есть полезная функция - ExtractFileExt
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.

Последний раз редактировалось dr. F.I.N., 31.01.2018 в 11:43.
Ответить с цитированием
Этот пользователь сказал Спасибо dr. F.I.N. за это полезное сообщение:
Taras2020 (31.01.2018)
  #7  
Старый 31.01.2018, 11:50
Taras2020 Taras2020 вне форума
Прохожий
 
Регистрация: 15.01.2018
Сообщения: 36
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от dr. F.I.N.
Не стал разбираться досконально с кодом, но что-то такое должно получится. Imikle все и так написал.
Отлично и спасибо. Сделал по вашей рекомендации и использовал функцию - ExtractFileExt. Все работает. Благодарю за помощь.

Последний раз редактировалось Taras2020, 31.01.2018 в 12:22.
Ответить с цитированием
  #8  
Старый 01.02.2018, 01:44
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,056
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

на самом деле зря вставил код в существующий. Я же не зря написал отдельную процку, просто ее надо было использовать, а то теперь получился размазанный по всей процедуре код.

Кстати, вот меня смущает такая строка:
Код:
if k = rL.Count then k := 0;
А значение в k потом нигде не используется. Нафига оно вообще?

И еще. Если у тебя много файлов, да еще и больших, то я бы подумал на тему написания многопоточного приложения.
Ответить с цитированием
  #9  
Старый 01.02.2018, 04:09
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Цитата:
Сообщение от lmikle
А значение в k потом нигде не используется. Нафига оно вообще?
Не внимательный
Код:
While Not EOF(F_Src) Do
    Begin
      ReadLN(F_Src,S);
      S := StringReplace(S, edt_Word.Text, rL.Strings[k], RF); //<-----rL.Strings[k]
      WriteLn(F_Tgt,S);
inc(k);
     if k = rL.Count then k := 0;
    End;
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.
Ответить с цитированием
  #10  
Старый 01.02.2018, 05:00
Аватар для @Rafa3L
@Rafa3L @Rafa3L вне форума
Начинающий
 
Регистрация: 09.11.2011
Адрес: Москва
Сообщения: 144
Версия Delphi: XE2
Репутация: 11216
По умолчанию

Цитата:
Сообщение от dr. F.I.N.
Не внимательный
А в таком варианте никогда не будет считана последняя строчка rL.Strings, инкремент нужно вниз переместить и k:=-1
4250
__________________
Помогаю платно.
Помогаю иногда бесплатно.
Ответить с цитированием
  #11  
Старый 01.02.2018, 05:39
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,056
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Цитата:
Сообщение от dr. F.I.N.
Не внимательный
Код:
While Not EOF(F_Src) Do
    Begin
      ReadLN(F_Src,S);
      S := StringReplace(S, edt_Word.Text, rL.Strings[k], RF); //<-----rL.Strings[k]
      WriteLn(F_Tgt,S);
inc(k);
     if k = rL.Count then k := 0;
    End;

Да бред какой-то получается.
Надо точно знать задачу. Что-то там точно не просто так.
Ответить с цитированием
  #12  
Старый 01.02.2018, 09:22
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Цитата:
Сообщение от @Rafa3L
А в таком варианте никогда не будет считана последняя строчка rL.Strings, инкремент нужно вниз переместить и k:=-1
4250
С чего это? Количество элементов COUNT. Нумерация элементов с 0 до COUNT-1. Если индекс=COUNT, значит уже вышли за предел, начинаем с первого элемента (0).
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.
Ответить с цитированием
  #13  
Старый 01.02.2018, 09:23
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
Хорошо

Цитата:
Сообщение от lmikle
Да бред какой-то получается.
Надо точно знать задачу. Что-то там точно не просто так.
Да судя по размеру входных файлов и (вероятно) их количеству, вообще все скинуть в поток нужно, иначе весь лог в Memo появится после окончания обработки. Так то да, каша а не процедура
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.
Ответить с цитированием
  #14  
Старый 02.02.2018, 05:56
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,056
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Ну, я то и написал выше.
А по поводу того, что бред - дык как-то мне не совсем понятен принцип замены. Исходя из размера данных.
Ответить с цитированием
  #15  
Старый 04.02.2018, 15:16
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Цитата:
Сообщение от Taras2020
Добрый день, уважаемые пользователи.
...
Так ты Тарас или Татьяна?
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 14:19.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter