На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
  
> Найти в файле сигнатуру и отрезаць от файла всё что до этой сигнатуры (быстро)
    Нужно найти в файле сигнатуру, и отрезать всё что от начала файла до этой сигнатуры, не подскажете каким способом это делается быстрее всего?
    Может есть уже какие библиотеки или примеры, компоненты для этого?
    Моя реализация на текущий момент через TmemoryStream, но мне кажется что можно быстрее..
      Подумать над реализацией двух случаев:
      1.Маленький файл (несколько МБ, до гига).
      2.Большой файл.
      В первом случае - всё прочитать махом в ОЗУ и там ужо найти и выписать хвост. Во втором - читать порциями, аккуратно в них искать сигнатуру (может быть на границе!), выписывать посегментно хвост.

      Добавлено
      Впрочем, может оказаться, что реализация только 2 варианта (даже с 16 КБ буфером) будет достаточной и быстрее всего. Но может оказаться, что сигнатура очень длинная (скажем, мегабайт), а тогда возникнет ряд проблем. :yes-sad:
        Тогда может оцените мой код, по сути нужно найти сигнатуру pdf файла и далее отсечь лишнее, сигнатура всего 4 байта, размер файла ну максимум 10mb, в среднем 1mb.
        Меня единственное что смущает так это мой поиск, но как сделать круче не знаю \ не умею ...


        ExpandedWrap disabled
          function ExtractPDFFromContainerAndSaveToFile(Stream: TStream; FileName: String; const StartPos: Cardinal = 500): Integer;
          var i: Cardinal; FStream: TStream;
          begin
            i:= StartPos;
            Result := -1;
            while i+4 < Stream.Size do
            begin
              if ( PByteArray(TMemoryStream(Stream).Memory)^[i] = $25) then
                  if
                     ( PByteArray(TMemoryStream(Stream).Memory)^[i+1] = $50) and
                     ( PByteArray(TMemoryStream(Stream).Memory)^[i+2] = $44) and
                     ( PByteArray(TMemoryStream(Stream).Memory)^[i+3] = $46)
                  then
                  begin
                    FStream := TFileStream.Create(FileName, fmCreate);
                    try
                     FStream.WriteBuffer(@PByteArray(TMemoryStream(Stream).Memory)^, i, Stream.Size-i);
                    finally
                     FStream.Free;
                     Result := 0;
                    end;
                    Exit;
                  end;
              Inc(i);
            end;
          end;
        Сообщение отредактировано: Jiro -
          Крайне невыгодно 4 раза по одному байту сравнивать (процессорно дорого). Я в Паскале крайне слаб, но точно можно же как-то перевести и сразу Dword'ы сравнить! (но шагать, конечно, всё равно по байтику надо!)
            Jiro, в твоем варианте нет смысла сравнивать побайтно, легче сразу сравнивать с 4-байтным числом. Но ты точно уверен, что сигнатура не будет располагаться, к примеру, с 2-го по 6-й байт?

            Славян
            Зависит от количества ложных срабатываний, возможно, быстрее классически искать первый байт и потом сравнивать хвосты.

            Jiro, 10 мб - это ничто, попробуй заюзать Pos для Ansi строк
            ExpandedWrap disabled
              SetLength(sFile, FileStream.Size);
              FileStream.ReadBuffer(sFile[1], FileStream.Size);
              sSign := RawByteString(#$25#$....);
              p := Pos(sSign, sFile);
              Цитата Fr0sT @
              Но ты точно уверен, что сигнатура не будет располагаться, к примеру, с 2-го по 6-й байт?

              Уверен.

              Fr0sT
              размер мусора в среднем 908 байт, ну там плюс\минус, в принципе можно начинать с позиции 500-того байта и буферить гденить 1024 байта и в них искать как вы предложили через Pos, но это итак понятно.

              Но вот тут возник вопрос сам собой, если использовать FileStream.ReadBuffer(sFile[1], FileStream.Size) то это получается
              лишнее копирование из памяти в память, насколько это быстро и затратно по ресурсам и можно ли избежать лишнего копирования передав данные в указатель и потом уже применять Pos?
                Цитата Jiro @
                это получается лишнее копирование из памяти в память

                А копирование и так и так будет. Но оно одно, и от него никуда не деться. Можно, конечно, извратиться через маппинг, но оптимизированной функции поиска по указателю в RTL нет, поэтому смысла в этом немного.
                А какие требования по быстродействию?
                  Цитата Fr0sT @
                  А какие требования по быстродействию?


                  Тут требований нету, это я так на будущее узнаю, мало ли пригодится.
                    Работа с диском на порядок-три медленнее, чем с памятью, так что скорость будет определяться именно им.
                      Кстати, было бы оптимально узнать начальные кластеры файла, а потом ненужные убрать и указать с какого байта начало. Но я технически не знаю, есть ли такая возможность, чтобы у гигабайтного, например, файла отрезать первые пару байт, но при этом не переписывать всё длинное тело?.. :-?
                        Славян
                        Насколько я понимаю, файл (по крайней мере, в старых файловых системах) стартует с начала кластера, т.е минимальная гранулярность перезаписи от 512 и т.п. байт
                          Да, я тоже так думал. Просто это же сильнейшее ограничение, кое могли как-то и побороть. В линухах (в btrfs?) наверняка ж можно!.. Ладно, пустое гадание; надо спецов поспрашивать. :oops:
                            Цитата Jiro @
                            while i+4 < Stream.Size do

                            наверное стоит добавить: while i+4 < Stream.Size-4 - чисто что бы не лезть за границы файлы...
                              Цитата Руслан @
                              наверное стоит добавить: while i+4 < Stream.Size-4 - чисто что бы не лезть за границы файлы...


                              выхода за границы не может быть, инкремент же на +1, а при нахождении сигнатуры выход.
                              файл итак читается не доходя до последних 4 байт, а в вашем случаи будет до 8 байт. ну как бы да, быстрее на пустых файлах, но тогда можно и 10 и 256 и тд ...


                              ну а если кому интересно то код теперь такой за что спс Fr0sT-у:

                              ExpandedWrap disabled
                                unction ExtractPDFFromContainerAndSaveToFile(Stream: TStream; FileName: String; const StartPos: Cardinal = 500): Integer;
                                var FStream: TStream;
                                    sSign: RawByteString; AData: AnsiString;  P: Int64;
                                begin
                                    Result := -1;
                                    SetLength(AData, 900+1024); //Буфер поиска, если искать по всему файлу то Stream.Size
                                    Stream.Position := StartPos;
                                    Stream.ReadBuffer(AData[1], 900+1024);//Буфер поиска, если искать по всему файлу то Stream.Size
                                    sSign  := RawByteString(#$25#$50#$44#$46);
                                    P      := StartPos + Pos(sSign, AData);
                                 
                                    if P > StartPos then
                                    begin
                                      FStream := TFileStream.Create(FileName, fmCreate);
                                      try
                                       FStream.WriteBuffer(@PByteArray(TMemoryStream(Stream).Memory)^, P-1, Stream.Size-P+1);
                                      finally
                                       FStream.Free;
                                       Result := 0;
                                      end;
                                    end;
                                end;
                              Сообщение отредактировано: Jiro -
                                Цитата Jiro @
                                файл итак читается не доходя до последних 4 байт

                                А, точно. Чёт я внесенные изменения проигнорил.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0399 ]   [ 17 queries used ]   [ Generated: 28.03.24, 17:24 GMT ]