Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Управление данными в TMemoryStream, Управление блоками памяти в TMemoryStrea 
V
    Опции темы
MuadDib
Дата 24.9.2007, 07:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 23.1.2007

Репутация: нет
Всего: нет



Здравствуйте, уважаемые. 
Возникла потребность работать с большими объемами данных помещенных в TMemotyStream объект. К примеру с большими файлами, загруженными в поток памяти. Необходимо удалять из памяти определенным образом помеченные блоки и соответствующим образом корректировать размер потока памяти.
Для работы с потоком памяти помимо его стандартных средств исползую указатель на его данные: 

код условно-описательный, чтобы показать, что делаю:

Код

TMemoryStream *MStream = new TMemoryStream;
char *MainBuf = (char*)MStream->Memory; //указывает на данные в потоке памяти

First(); //на начало
while(!Eof()) //пока не конец блока
{
if(CheckDelRecord()) //проверка на признак необходимости удаления записи
{
MoveMemory((MainBuf + Offset1),(MainBuf + Offset2),MStream->Size - Offset2); //копируем данные со смещения Offset2 на 
//Offset1 размером от Offset2 до конца файл
//т.е. "подтягиваем" на место удаленного блока все остльные данные 
MStream->SetSize(Offset1 - Offset2);//и уменьшаем размер потока памяти на количество "удаленных" байт
}
else
Next();
}


Данных код нормально работает, с файлами не слишком большого размера. С большими файлами - очень медленно.

Еще вариант, тоже условно-описательный:

Код

First();
int R = 0,
N = 0,
K = 0;

while(K != RecordCount) //RecordCount - количество записей т.е. блоков данных определенного размера в потоке памяти
{
K = N;
FCurrentRecord = N; //указывает на текущую запись

if(CheckDelRecord()) //если запись нужно удалить
{
if(K == RecordCount)
break;

FCurrentRecord = firstNDRec;
while((K++ != RecordCount) && (CheckDelRecord())) //ищем следующую запись которую удалять не нужно
FCurrentRecord = firstNDRec = K ;

if(!CheckDelRecord()) //если нашли
{
FCurrentRecord = R = N; //для рассчета смещений Offset1 и Offset2 описание расчета не привожу для краткости 
MoveMemory((MainBuf + Offset1),(MainBuf + Offset2),RecordSize); //копируем данные из "неудаленной" записи в ту область которую "удалить" нужно
FCurrentRecord = K;
DeleteRecord(); //помечаем скопированную запись чтобы удалить ее когда до нее доберемся дабы не делать дубли 
}
}
else
R = N;
}

if(R == 0)
Empty();
else
MStream->SetSize(MStream->Size - RecordSize * (RecordCount - R)); //ну и в конце уменьшаем размер потока до необходимого


Данных код тоже работает нормально с файлами не слишком большого размера. С большими файлами медленно, хотя и быстрее чем предыдущий.
Подскажите пожалуйста, как еще можно реализовать данную задачу с наибольшим быстродействием. Интересует именно быстродействие, затраченные ресурсы неважны. 
Заранее спасибо!
PM MAIL   Вверх
Mihhail
Дата 24.9.2007, 09:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 96
Регистрация: 13.9.2007

Репутация: нет
Всего: 9



Цитата(MuadDib @  24.9.2007,  11:31 Найти цитируемый пост)
//RecordCount - количество записей т.е. блоков данных определенного размера в потоке памяти

Если все записи одинакового размера, то почему бы не перемещать на место удалённой записи самую последнюю запись из "хвоста".

И зачем постоянно менять размер выделенной памяти если:
Цитата(MuadDib @  24.9.2007,  11:31 Найти цитируемый пост)
 Интересует именно быстродействие, затраченные ресурсы неважны.

При необходимости можно только увеличивать выделеный блок, при чём с запасом. Ведь известно кол-во записей и выход на удалённые ("мусорные") участки исключён. Если идёт постоянное Del/Add записей это так же увеличит скорость.
PM MAIL WWW   Вверх
MuadDib
Дата 24.9.2007, 09:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 23.1.2007

Репутация: нет
Всего: нет



Если все записи одинакового размера, то почему бы не перемещать на место удалённой записи самую последнюю запись из "хвоста".

Добавлено через 4 минуты и 58 секунд
Дело в том, что данные в потоке должны следовать в том порядке, в котором они были туда загружены, менять последовательность нельзя. Т.е. на место удаленного блока должен вставать следующий непомеченный к удалению блок. Размер выделенной памяти действительно можно изменять не каждый раз, а только единожды после всех операций по перемещению данных, как это сделано во втором примере, однако это не дает ощутимого результата.
PM MAIL   Вверх
Mihhail
Дата 24.9.2007, 11:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 96
Регистрация: 13.9.2007

Репутация: нет
Всего: 9



Цитата(MuadDib @  24.9.2007,  13:34 Найти цитируемый пост)
 Размер выделенной памяти действительно можно изменять не каждый раз, а только единожды после всех операций по перемещению данных

Я имею в виду не изменять размер даже в этом случае. Освобождать память только при завершении программы.

А по алгоритму могу предложить следующее:
Цитата(MuadDib @  24.9.2007,  13:34 Найти цитируемый пост)
 на место удаленного блока должен вставать следующий непомеченный к удалению блок

  Время перемещения всех записей всё равно не уменьшить, но можно сделать что бы программа не зависала, т.е. не перемещать все записи за раз. А создавать отдельный поток или просто таймер, который через небольшие промежутки времени смещает блоки небольшой длины(поэксперементировать с их размером). Пока единственное что приходит в голову....

Добавлено через 3 мин
А если забить на это перемещение? Нам же известны номера удалённых записей, при просмотре просто перескакивать через них.

Это сообщение отредактировал(а) Mihhail - 24.9.2007, 11:15
PM MAIL WWW   Вверх
Alexeis
Дата 24.9.2007, 11:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 26
Всего: 459



Цитата(MuadDib @  24.9.2007,  07:31 Найти цитируемый пост)
Данных код нормально работает, с файлами не слишком большого размера. С большими файлами - очень медленно.

  Перед тем как придумывать определите какие файлы являются большими и каких ресурсов не жалко. Все таки файлы бывают и 100Гб, а в ОЗУ выделить непрерывный блок в 1Гиг порой невозможно. 


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Vyacheslav
Дата 24.9.2007, 12:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2124
Регистрация: 25.3.2002
Где: Москва

Репутация: 47
Всего: 59



А зачем в приницпе держать это все в  TMemotyStream  постоянно? А если уж это так нужно, то почему не использовать вектор объектов TMemotyStream?


--------------------
С уважением, Вячеслав Ермолаев
PM MAIL WWW ICQ   Вверх
MuadDib
Дата 24.9.2007, 12:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 23.1.2007

Репутация: нет
Всего: нет



Если вывести упаковку в отдельный поток на длительное время (т.к. файл размером, например 200 МБ будет паковаться достаточно долго) , получится, что работать с данными будет все равно нельзя, так как они будут постянно изменяться и не будут актуальны. Это получится как работа с реляционной БД в отсутствии транзакций - не знаешь есть ли физически запись в потоке с которой собираешься работать или нет ее и подобные проблемы. Забить тоже нельзя, т.к. смысл упаковки в том, чтобы в конечном итоге уменьшить размер конечного потока и сохранить его в файл. Т.е. ресурсозатраты неважны на этапе работы с потоком, но затем файл, сформированный в итоге должен занять возможный минимум дискового пространства.
Такая вот неприятная штука получается... Нужно и с елки съехать и, желательно, седалище не оцарапать
PM MAIL   Вверх
MuadDib
Дата 24.9.2007, 12:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 23.1.2007

Репутация: нет
Всего: нет



Если не затруднит, хотелось бы попросить Ермолаева Вячеслава привести пример корректного создания вектора объектов TMemoryStream и работы с ним. 
Дело в том, что по-моему вариант: vector <TMemoryStream *> не слишком подходит. Желательно, как мне кажется, хранить не указатели, а сами потоки. И т.к. я не имею большого опыта работы с векторами не соображу как сделать верно... Хотя идея такая тоже приходила.
PM MAIL   Вверх
Alexeis
Дата 24.9.2007, 12:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 26
Всего: 459



Предлагаю такой алгоритм. Сначала расчитать где должна быть каждая из записей, затем выделить новый блок нужной длинны и за один проход скопировать каждый блок строго на свое место. скопировать 200Мб в памяти это довольно быстро, должно быть не более 1й секунды.

Добавлено через 1 минуту и 48 секунд
Цитата(MuadDib @  24.9.2007,  12:39 Найти цитируемый пост)
Дело в том, что по-моему вариант: vector <TMemoryStream *> не слишком подходит.

  TMemoryStream - это клас VCL, потому не может быть статическим. 


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
MuadDib
Дата 24.9.2007, 12:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 23.1.2007

Репутация: нет
Всего: нет



Alexeis, я заню, что TMemoryStream не может быть статическим. А предложенный алгоритм начинаю писать, по-моему дельно, нужно пробовать...


PM MAIL   Вверх
Vyacheslav
Дата 24.9.2007, 14:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2124
Регистрация: 25.3.2002
Где: Москва

Репутация: 47
Всего: 59



Цитата(MuadDib @  24.9.2007,  12:39 Найти цитируемый пост)
Дело в том, что по-моему вариант: vector <TMemoryStream *> не слишком подходит. Желательно, как мне кажется, хранить не указатели, а сами потоки. И т.к. я не имею большого опыта работы с векторами не соображу как сделать верно... 

Кстати как раз удобнее во всех случаях хранить указатели. Сэкономите на копировании.
Если информацию, удалять-не удалять можно выудить из самого содержимого, то весь Ваш код по сжатию  уложится в  строкe плюс небольшая модификация CheckDelRecord( пишу по памяти без среды, поэтому могут быть ошибки )

Код


vector<TMemoryStream> vec;
bool CheckDelRecord(TMemoryStream* stream) 
{
     bool isDeleted = false;
     //здесь код по проверке нужно ли удалять 
     ...
     isDeleted = ...
     if( (isDeleted ) 
     {
          delete stream;
      }
     return isDeleted;
    
}

vec.erase( remove_if(vec.begin(), vec.end(),  CheckDelRecord ), vec.end());


 


--------------------
С уважением, Вячеслав Ермолаев
PM MAIL WWW ICQ   Вверх
MuadDib
Дата 25.9.2007, 13:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 23.1.2007

Репутация: нет
Всего: нет



Всем спасибо, получилос сделать через вектор быстро и удобно. 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.1246 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.