|
Вопрос # 4 864/ вопрос решён / |
|
Здравствуйте, эксперты!
У меня Delphi 7 и вот такая проблема. Имею TStream с данными. Причём данные произвольные не имеющие какой то структуры. Нужно найти в этих данных другие данные и узнать позицию их в потоке. Пробовал считывать все данные из потока в PChar а затем с помощью функции AnsiStrPos произвести поиск, но вот беда, в потоке есть нулевые символы которые PChar "считает" концом строки. Если есть возможность дайте быструю функцию поиска данных ибо через цикл у меня как то медленно всё работает. Спасбо. Пришлите пожалуйста ответ на amber8706@mail.ru или ссылку на него.
 |
Вопрос задал: amber (статус: 1-ый класс)
Вопрос отправлен: 26 декабря 2010, 16:26
Состояние вопроса: решён, ответов: 0.
|
Мини-форум вопроса
Всего сообщений: 15; последнее сообщение — 21 января 2011, 13:21; участников в обсуждении: 5.
|
min@y™ (статус: Доктор наук), 26 декабря 2010, 16:31 [#1]:
Давай-ка по-конкретнее, что нужно искать. В чём хранятся данные (шаблон) для поиска?
Всё делается гораздо проще, чем ты думаешь. Не надо ничего никуда копировать, можно (нужно!) искать прямо в стриме.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
amber (статус: 1-ый класс), 26 декабря 2010, 16:54 [#2]:
есть IdHTTPServer, браузер отсылает ему форму с прикрепленным фалом(ми). Данные формы и сами файлы находятся в параметре ARequestInfo.PostStream события OnCommandGet. Я пытался считать все данные из потока в PChar и с помощью AnsiStrPos разбить поток на элементы: заголовок запроса\данные, т.е. отделить одно от другого и привести в более "опрятный" вид, создав коллекцию из этих элементов. Так вот в чём проблема: если в присылаемых данных нет нулевых символов функция AnsiStrPos и всё с ней связанное работает нормально. Разделение данных создание коллекции происходит без проблем, НО если в данных встречается символ с кодом 0 функция AnsiStrPos и сё с ней связанное не работает! Может я изобретаю велосипед и данную проблему уже решили?
|
|
min@y™ (статус: Доктор наук), 26 декабря 2010, 17:05 [#3]:
Мне таких подробностей не надо.
Ты на мой вопрос не ответил.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
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™ (статус: Доктор наук), 26 декабря 2010, 18:06 [#5]:
А искать-то что надо?
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
min@y™ (статус: Доктор наук), 26 декабря 2010, 18:09 [#6]:
Для поиска нужно только одно - то, что искать. В любом буфере, будь то массив, строка, указатель на кусок памяти и т.д.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
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 (статус: 1-ый класс), 26 декабря 2010, 19:35 [#8]:
Я ж написал, что нужно отделить "Content-Disposition" от данных. Вышеприведённое содержимое потока было примером. Через Ваш код это сделать то можно, но для больших данных он не годится, поскольку работать будет медленно. Алгоритм должен быть примерно таким:
Считываем строку-разделитель (в примере она выглядит как "-----------------------------7da31c3510562"
Считываем заголовки "Content-Disposition" каждого блока данных, разделанных ранее полученной строкой.
Считываем данные каждого блока .
Вся сложность заключается в БЫСТРОМ поиске в потоке строки-разделителя. Я использовал для её поиска AnsiStrPos, но как я сказал ранее, эта функция не дружит с нулевыми символами.
P.S.
Представляете сколько будет "Думать" приведенная Вами функция если размер потока, скажем 1Гб, а нужное число находится в его конце? Но смысл я вижу Вам стал понятен.
|
|
min@y™ (статус: Доктор наук), 26 декабря 2010, 20:03 [#9]:
Цитата (amber):
Представляете сколько будет "Думать" приведенная Вами функция если размер потока, скажем 1Гб, а нужное число находится в его конце?
Да, но это частный случай. Можно сделать немного по-другому. Читать блоками по, например, 64 кб, искать там начало, запоминать индекс и дальше выдирать из стрима блок нужного размера и сравнивать. Всё будет быстро и просто.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
bugmenot (статус: 3-ий класс), 26 декабря 2010, 23:06 [#10]:
функция SearchBuf, кстати, Pos тоже binary-safe
и вообще это стандартный multipart/form-data
виконання програми розпочинається з того самого мiсця, де призупинилося.
|
|
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 (статус: Посетитель), 28 декабря 2010, 23:12 [#13]:
Короче... 32 или 64 по боку! Я вкурсе чё ты там хочешь рубануть... тупо делай s:= TStringList.creaTE... а дальше делай свё по теме.
|
|
eclipse (статус: Посетитель), 28 декабря 2010, 23:19 [#14]:
Да короче даже дело не в оперативки... как ты прогу юзаешь... тупо опиши.
|
21 января 2011, 13:20: Статус вопроса изменён на решённый (изменил автор вопроса — amber)
|
amber (статус: 1-ый класс), 21 января 2011, 13:21 [#15]:
Спасибо всем, всё получилось!
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|