Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 4 864

Раздел: Delphi » Прочее
/ вопрос решён /

Здравствуйте, эксперты!
У меня Delphi 7 и вот такая проблема. Имею TStream с данными. Причём данные произвольные не имеющие какой то структуры. Нужно найти в этих данных другие данные и узнать позицию их в потоке. Пробовал считывать все данные из потока в PChar а затем с помощью функции AnsiStrPos произвести поиск, но вот беда, в потоке есть нулевые символы которые PChar "считает" концом строки. Если есть возможность дайте быструю функцию поиска данных ибо через цикл у меня как то медленно всё работает. Спасбо. Пришлите пожалуйста ответ на amber8706@mail.ru или ссылку на него.

amber Вопрос решён, но можно продолжить его обсуждение в мини-форуме

Вопрос задал: amber (статус: 1-ый класс)
Вопрос отправлен: 26 декабря 2010, 16:26
Состояние вопроса: решён, ответов: 0.


Мини-форум вопроса

Всего сообщений: 15; последнее сообщение — 21 января 2011, 13:21; участников в обсуждении: 5.
min@y™

min@y™ (статус: Доктор наук), 26 декабря 2010, 16:31 [#1]:

Давай-ка по-конкретнее, что нужно искать. В чём хранятся данные (шаблон) для поиска?
Всё делается гораздо проще, чем ты думаешь. Не надо ничего никуда копировать, можно (нужно!) искать прямо в стриме.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
amber

amber (статус: 1-ый класс), 26 декабря 2010, 16:54 [#2]:

есть IdHTTPServer, браузер отсылает ему форму с прикрепленным фалом(ми). Данные формы и сами файлы находятся в параметре ARequestInfo.PostStream события OnCommandGet. Я пытался считать все данные из потока в PChar и с помощью AnsiStrPos разбить поток на элементы: заголовок запроса\данные, т.е. отделить одно от другого и привести в более "опрятный" вид, создав коллекцию из этих элементов. Так вот в чём проблема: если в присылаемых данных нет нулевых символов функция AnsiStrPos и всё с ней связанное работает нормально. Разделение данных создание коллекции происходит без проблем, НО если в данных встречается символ с кодом 0 функция AnsiStrPos и сё с ней связанное не работает! Может я изобретаю велосипед и данную проблему уже решили?
min@y™

min@y™ (статус: Доктор наук), 26 декабря 2010, 17:05 [#3]:

Мне таких подробностей не надо.
Ты на мой вопрос не ответил.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
amber

amber (статус: 1-ый класс), 26 декабря 2010, 17:45 [#4]:

Вот пример содержимого патока (TStream):

-----------------------------7da31c3510562
Content-Disposition: form-data; name="path"

C:\
-----------------------------7da31c3510562
Content-Disposition: form-data; name="PutFile"; filename="primer.txt"
Content-Type: text/plain

ПРИМЕР!!
-----------------------------7da31c3510562
Content-Disposition: form-data; name="submit"

Закачать
-----------------------------7da31c3510562--

Нужно отделить "Content-Disposition:" от данных, т.е. на выходе хотелось бы видеть следующее:

Массив строк (или TStrings) вида:

Content-Disposition: form-data; name="path"

Content-Disposition: form-data; name="PutFile"; filename="primer.txt"
Content-Type: text/plain

Content-Disposition: form-data; name="submit"

Массив данных, вида:

C:\

ПРИМЕР!!

Закачать

Разумеется данные могут быть двоичными, но строки всегда имеют текстовый вид, кроме того строка "-----------------------------7da31c3510562" может быть какой угодно, но всегда имеет вид: "----ххх"

Сам поток может содержать сколько угодно данных, разделанных строкой вида: "----ххх", но начинается он всегда с строки "----ххх", а заканчивается всегда строкой вида: "----ххх--"
min@y™

min@y™ (статус: Доктор наук), 26 декабря 2010, 18:06 [#5]:

А искать-то что надо?
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
min@y™

min@y™ (статус: Доктор наук), 26 декабря 2010, 18:09 [#6]:

Для поиска нужно только одно - то, что искать. В любом буфере, будь то массив, строка, указатель на кусок памяти и т.д.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
min@y™

min@y™ (статус: Доктор наук), 26 декабря 2010, 18:11 [#7]:

Вот, например, функция поиска 4-байтного целого в стриме:
unit General;
 
interface
 
uses
  Messages, Classes;
 
type
  TProgressCallback = procedure(const Progress: Integer) of object;
  TSuccessCallback = procedure(const Address: Int64) of object;
 
const
  WM_RANDOM_VALUE =             WM_USER + 100;
  TargetWindowClassName =       'TTargetMainForm';
  TargetWindowTitle =           'Приложение - цель';
  MainWindowClassName =         'TMainForm';
  MainWindowTitle =             'Управляющее приложение';
 
var
  FindNextAddress: Cardinal = 0;
 
// Поиск адреса первого вхождения 4-байтного целого в потоке
// Возвращает кол-во вхождений.
// вызывает cbProgress() при увеличении прогресса на 1%
// вызывает cbSuccess() при нахождении очередного вхождения
function FindValueInStream(const Value: Cardinal;
                           Stream: TStream;
                           cbProgress: TProgressCallback;
                           cbSuccess: TSuccessCallback): Cardinal;
 
implementation
 
function FindValueInStream(const Value: Cardinal;
                           Stream: TStream;
                           cbProgress: TProgressCallback;
                           cbSuccess: TSuccessCallback): Cardinal;
var
  MayBe: Cardinal;
  B,
  LeftByte: Byte;  // мл. байт
  Progress, OldProgress: Integer;
begin
  Result:= 0;
  if not Assigned(cbSuccess)
    then Exit;
 
  OldProgress:= 0;
 
  if Stream.Position <> 0
    then Stream.Position:= 0;
 
  LeftByte:= Value and $FF;
  while Stream.Position < Stream.Size do
    begin
      if Stream.Read(B, 1) <> 1
        then Exit;
 
      if B <> LeftByte
        then Continue
        else begin
               if Stream.Read(MayBe, 3) <> 3
                 then Exit; // читаю 3 остальных байта
               MayBe:= (MayBe shl 8) + B; // Соединяю с младшим байтом
 
               if Value = MayBe
                 then begin
                        Inc(Result);
                        cbSuccess(Stream.Position - 4)
                      end
                 else Stream.Seek(-3, soFromCurrent);
             end;
 
      // Вызов события по прогрессу
      if Assigned(cbProgress)
        then begin
               Progress:= Round(100 * Stream.Position / Stream.Size);
               if Progress <> OldProgress
                 then begin
                        OldProgress:= Progress;
                        cbProgress(Progress);
                      end;
             end;
    end;
end;
 
end.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
amber

amber (статус: 1-ый класс), 26 декабря 2010, 19:35 [#8]:

Я ж написал, что нужно отделить "Content-Disposition" от данных. Вышеприведённое содержимое потока было примером. Через Ваш код это сделать то можно, но для больших данных он не годится, поскольку работать будет медленно. Алгоритм должен быть примерно таким:

Считываем строку-разделитель (в примере она выглядит как "-----------------------------7da31c3510562"

Считываем заголовки "Content-Disposition" каждого блока данных, разделанных ранее полученной строкой.

Считываем данные каждого блока .

Вся сложность заключается в БЫСТРОМ поиске в потоке строки-разделителя. Я использовал для её поиска AnsiStrPos, но как я сказал ранее, эта функция не дружит с нулевыми символами.

P.S.
Представляете сколько будет "Думать" приведенная Вами функция если размер потока, скажем 1Гб, а нужное число находится в его конце? Но смысл я вижу Вам стал понятен.
min@y™

min@y™ (статус: Доктор наук), 26 декабря 2010, 20:03 [#9]:

Цитата (amber):

Представляете сколько будет "Думать" приведенная Вами функция если размер потока, скажем 1Гб, а нужное число находится в его конце?

Да, но это частный случай. Можно сделать немного по-другому. Читать блоками по, например, 64 кб, искать там начало, запоминать индекс и дальше выдирать из стрима блок нужного размера и сравнивать. Всё будет быстро и просто.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
bugmenot

bugmenot (статус: 3-ий класс), 26 декабря 2010, 23:06 [#10]:

функция SearchBuf, кстати, Pos тоже binary-safe

и вообще это стандартный multipart/form-data
виконання програми розпочинається з того самого мiсця, де призупинилося.

amber

amber (статус: 1-ый класс), 27 декабря 2010, 12:58 [#11]:

Спасибо за SearchBuf! Всё работает быстро и с большими объёмами данных (до нескольких сотен мегабайт). с гигабайтными потоками правда проблема. При попытке считать их в переменную пишет, что не хватает памяти (хотя на компьютере у меня 8Гб оперативки из них Windows видит 4Гб (ОС 32 битная)). Попробую использовать метод, описанный min@y™, считывать в память по несколько килобайт и обрабатывать их (правда это будет немного геморойно и скорее всего дольше. Проще наверно запретить пользователю отправлять файлы больше определённого размера), но всё равно всем спасибо!
Вадим К

Вадим К (статус: Академик), 27 декабря 2010, 13:58 [#12]:

Цитата (amber):

(хотя на компьютере у меня 8Гб оперативки из них Windows видит 4Гб (ОС 32 битная))

Нужно ставить 64битную ось. Хотя это может не помочь - ещё процессор и материнская плата должна видеть.
на 32битной системе выделить больше 2 гигов памяти одним куском без специальных приспособлений нельзя.
Но даже если все приспособления заюзать, больше 3 гигов нераздельно не выделить.
Но спрашивается, зачем обрабатывать гигабайтные потоки? В чем же там таком ищется. Если это http ответы обрабатываются, то есть смысл смотреть только начало стрима.
Галочка "подтверждения прочтения" - вселенское зло.
eclipse

eclipse (статус: Посетитель), 28 декабря 2010, 23:12 [#13]:

Короче... 32 или 64 по боку! Я вкурсе чё ты там хочешь рубануть... тупо делай s:= TStringList.creaTE... а дальше делай свё по теме.
eclipse

eclipse (статус: Посетитель), 28 декабря 2010, 23:19 [#14]:

Да короче даже дело не в оперативки... как ты прогу юзаешь... тупо опиши.

21 января 2011, 13:20: Статус вопроса изменён на решённый (изменил автор вопроса — amber)

amber

amber (статус: 1-ый класс), 21 января 2011, 13:21 [#15]:

Спасибо всем, всё получилось!

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:36
Выполнено за 0.03 сек.