Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Проблема с процедурой [D7, XP]


v_a_belousov ©   (2010-10-01 03:14:00) 

Здравствуйте! Есть процедура

procedure TReaderMainForm.AddFileToList(List: TStrings; const SFileName: String);
//переменные
var CText: string;
begin
//проверяем тип файла
if GetFileTypeAtExt(ExtractFileExt(SFileName))<>EmptyType then
begin
 // Добавляем после проверки - есть там уже такое имя или нет
 if List.IndexOf(ExtractCName(ExtractFileName(SFileName))) = -1 then
  begin
   //очищаем переменную
   CText := VPlayList.CommaText;
   List.Add(ExtractCName(ExtractFileName(SFileName)));
   //указываем
   VPlayList.NameValueSeparator := '=';
   //если в переменную ещё ничегго не записано, то
   if CText<>'' then //такой вид записи не подходит
   CText := CText + ', ' + '"' + ExtractFileName(SFileName) + '=' +
   SFileName + '"' else //значит пишем так
   CText := '"' + ExtractFileName(SFileName) + '=' + SFileName + '"';
   //добавляем в список
   VPlayList.CommaText := CText;
  end;
end;
end;

вот сразу код сопутствующей функции
function TReaderMainForm.GetFileTypeAtExt(FExt: string): TFileType;
var i: integer; //счетчик
begin
//ищем заданное расширение среди видеотипов
for i:=0 to Length(VideoExts)-1 do
begin
 //если найден, то
 if AnsiUpperCase(VideoExts[i]) = AnsiUpperCase(FExt) then
  begin
   //сообщаем что это видеофайл
   result := VideoType;
   //выходим
   exit;
  end;
end;
//ищем заданное расширение среди аудиотипов
for i:=0 to Length(AudioExts)-1 do
begin
 //если найден, то
 if AnsiUpperCase(AudioExts[i]) = AnsiUpperCase(FExt) then
  begin
   //сообщаем что это аудиофайл
   result := AudioType;
   //выходим
   exit;
  end;
end;
//ищем заданное расширение среди графических типов
for i:=0 to Length(PictureExts)-1 do
begin
 //если найден, то
 if AnsiUpperCase(PictureExts[i]) = AnsiUpperCase(FExt) then
  begin
   //сообщаем что это графический файл
   result := PictureType;
   //выходим
   exit;
  end;
end;
//если не совпадает не с одним из вышеперечисленных, то значит пусто
Result := EmptyType;
end;

В цикле добавляю файлы в список

 //добавляем файлы из папок и их подпапок в список
 for i:=0 to DropFiles_List.Count-1 do
  begin
   //добавляем имя в список
   ReaderMainForm.AddFileToList(ReaderMainForm.PlayList_LB.Items, DropFiles_List.Strings[i]);
   //Не даем зависнуть
   Application.ProcessMessages;
  end;

Проблема в том что примерно после 17000 файлов которые добавляются за пару секунд до 18000 файлов проходит уже секунд 30 а до 18500 файлов тратится ещё почти минута. Подскажите пожалуйста что я не правильно делаю.


RWolf   (2010-10-01 09:57:00) [1]

насколько я понимаю, принципиальная ошибка здесь в использовании наследника TStrings — контейнера со временем поиска O(n) — для хранения данных вида "имя-значение"; здесь больше подошло бы что-то вроде хэш-таблицы (см. библиотеку Delphi Fundamentals, например).


Apollo   (2010-10-01 07:09:00) [2]

Такие объемы лучше грузить не в линейный список, а использовать какую-то структуру, по типу древовидной, чтобы ограничивать объем одновременно загружаемых и выводимых данных.

Но если очень хочется линейный список, то лучше тогда грузить и обрабатывать весь список в TStringList в отдельном потоке, а потом уже грузить этот TStringList в ListBox.

Но если и этого не хочется, то не вызывай так часто Application.ProcessMessages, делай один вызов на 10, 100 добавлений:
if i mod 100 = 0 then
 Application.ProcessMessages;


Кроме того, перед циклом добавления можно вызвать ListBox.Items.BeginUpdate, а после цикла - ListBox.Items.EndUpdate. Это заблокирует визуальное обновление списка на время добавления, что ускорит весь процесс. Хотя, может, тебе нравятся визуальные эффекты при загрузке списка...

Еще, у тебя несколько раз встречается вызов   ExtractCName(), ExtractFileName(). Заведи в методе добавления пару локальных переменных, в самом начале метода один раз выполни FN := ExtractFileName()и CN := ExtractCName(FN)(кстати, что это за функция?), и пользуйся далее полученными значениями.

Еще замечания по поводу AnsiUpperCase(VideoExts[i]) = AnsiUpperCase(FExt).
VideoExts (как и другие списки расширений) у тебя уже заранее должны быть в верхнем регистре, чтобы не выполнять при каждо проверке преобразование.

Мне я ошибаюсь, но мне кажется, что здесь много лишней работы: CText := VPlayList.CommaText;...(и прочие движения с CommaText). Может, сделать вот так: VPlayList.Values[FN] := SFileName?

В общем, логика работы по добавлению файлов мне не совсем понятна. Если уточнишь, может, будут другие советы. А пока извини, если что не так...


MBo   (2010-10-01 06:00:00) [3]

Всё не смотрел, но поиск IndexOf для больших списков медленный. Да еще и в визуальном компоненте.
Сортированный TStringList + Find

Кроме того, для каждого файла в CommaText и назад, насколько я понял, гоняется большая строка. Это необходимо? Что там за логика подразумевается?


v_a_belousov   (2010-10-01 03:42:00) [4]

хотел бы уточнить. Файлы добавляются переносом из проводника(если папка, то производится поиск файлов во всех подпапках). Попробовал сейчас перенести диск D на ListBox зависло на 9000(из 16000) файлов, с диска E на 17000(из 94000) файлов а с диска F за пару секунд перенес 21000 файлов(все найденные).


Наверх

Титульная страница Поиск, карта сайта Написать письмо