Delphi: как эффективно прочитать большой двоичный файл, преобразовав его в шестнадцатеричный формат для передачи его в качестве параметра varbinary (max)? - PullRequest
2 голосов
/ 12 мая 2010

Мне нужно преобразовать двоичный файл (zip-файл) в шестнадцатеричное представление, чтобы затем отправить его на sql-сервер в качестве параметра функции varbinary (max).

Полный пример (с использованием очень маленького файла!):

1) мой файл содержит следующие биты 0000111100001111

2) Мне нужна процедура, чтобы БЫСТРО преобразовать ее в 0F0F

3) Я буду вызывать функцию сервера sql, передавая 0x0F0F в качестве параметра

Проблема в том, что у меня есть большие файлы (до 100 МБ, даже если возможен размер файла 100 КБ), поэтому мне нужен самый быстрый способ сделать это.

В противном случае указано: мне нужно создать строку

'0x'+BinaryDataInHexadecimalRepresentation

самым эффективным способом. (Примечание: может быть, есть способ немедленно открыть файл и получить шестнадцатеричную строку, поэтому в этом случае все, что мне нужно, это использовать «этот путь», если он есть).

Смежный вопрос: передача шестнадцатеричных данных на сервер sql

ОБНОВЛЕНИЕ : после прочтения комментариев я думаю, что здесь необходимо добавить больше информации. Причина, по которой я пытаюсь использовать текстовую команду T-SQL для отправки двоичных данных в хранимую процедуру, заключается в том, что таким образом я снимаю некоторые издержки на сервер: сохраненный prcoedure получает двоичные данные и записывает их в файл (это моя конечная цель). Если я использую компонент DAC, я смогу легко отправлять данные biray на сервер, но в этом случае мне нужно использовать временную таблицу для хранения данных, а затем отправлять эти данные в хранимую процедуру, которая записывает файл.

Итак, идея такова:

1) использование T-SQL «длинной» команды: больше накладных расходов на клиенте, потому что мне нужно прочитать файл и преобразовать его в шестнадцатеричное для подготовки длинной команды; меньше нагрузки на сервер, так как сервер sql просто получает двоичные данные и обрабатывает их в хранимой функции

2) с использованием DAC: мне нужно пройти через временную таблицу на сервере sql, поэтому на сервере больше накладных расходов

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

1 Ответ

1 голос
/ 12 мая 2010

Ну, вот вариант, который сделает преобразование настолько быстрым, насколько я могу себе представить.

Особенности кода:

  • Только одно выделение для строки (поэтому нет realloc и нет перемещения или копирования)
  • Быстрое чтение из файла.

Поскольку мы знаем, что один байт преобразуется ровно в два шестнадцатеричных символа, мы знаем, что наша строка результата должна быть в два раза больше размера файла. Мы выделяем строку требуемого размера и затем читаем из файла достаточно большими блоками, чтобы ОС могла оптимизировать ее для нас (чтение побайтов - зло). Мы используем фактическую строку, но мы записываем в строку, используя указатель:

function TEditorDeschidereDeCredite.FileToHex(FileName: string): AnsiString;
var FS:TFileStream;
    PS:PAnsiChar;
    Block:array[0..1023] of byte; // 1Kb
    len,i,pos:Integer;
    B:Byte;
const Nibbs: array[0..15] of AnsiChar = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
begin
  FS := TFileStream.Create(FileName, fmOpenRead);
  try
    Result := '';
    SetLength(Result, FS.Size * 2);
    PS := PAnsiChar(Result);
    pos := 0; // position into the result string
    len := FS.Read(Block, SizeOf(Block));
    while len <> 0 do
    begin
      for i:=0 to len-1 do
      begin
        B := Block[i];
        PS[pos] := Nibbs[B div $F];
        Inc(pos);
        PS[pos] := Nibbs[B mod $F];
        Inc(pos);
      end;
      len := FS.Read(Block, SizeOf(Block));
    end;
  finally FS.Free;
  end;
end;

P.S .: Я использую AnsiString и PAnsiChar, поэтому код работает и с Unicode Delphi. Если вы оказались в Delphi 2010, найдите способ использовать это в его текущей форме (AnsiString), чтобы вы могли пропустить преобразования.

...