Как мне преобразовать массив байтов в строку с помощью Delphi?

#delphi #delphi-7

#delphi #delphi-7

Вопрос:

Я разрабатываю проект с помощью Delphi и хочу преобразовать массив байтов в строковый тип. Как я могу это сделать?

Примеры кодов C #:

 private void ListenerOnDataTransmit(DataTransmitEventArgs e)
{
    transmittedMsg = BitConverter.ToString(e.TransmittedBytes, 0, e.TransmittedBytes.Length);
    try { Invoke(new EventHandler(UpdateTransmittedMessagesListView)); }
    catch { }
}
 

Комментарии:

1. Вы забыли сказать нам, что вы подразумеваете под «преобразованием массива байтов в строку». Существует несколько различных интерпретаций, все разумные: (1) обработайте массив байтов как ASCII и получите кодируемый им текст; (2) обработайте массив байтов как UTF8 и получите кодируемый им текст; (3) получите необработанное шестнадцатеричное представление массива данных; (4) получите необработанныйдвоичное представление массива данных; и т.д. В последних случаях вы хотите сгруппировать цифры?

Ответ №1:

BitConverter.ToString() Метод «Преобразует числовое значение каждого элемента указанного массива байтов в эквивалентное шестнадцатеричное строковое представление». Вы можете сделать то же самое вручную в Delphi 7, используя SysUtils.IntToHex() функцию в цикле, например:

 uses
  ..., SysUtils;

var
  bytes: array of byte;
  s: string;
  i: Integer;
begin
  bytes := ...;
  s := '';
  if bytes <> nil then
  begin
    s := IntToHex(bytes[0], 2);
    for i := 1 to High(bytes) do
      s := s   '-'   IntToHex(bytes[i], 2);
  end;
end;
 

Комментарии:

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

2. @AndreasRejbrand Да, есть много разных способов подойти к этому. Выше приведен только один пример.

3. Верно. И для небольших буферов это, безусловно, достаточно хорошо, так что 1.

4. По крайней мере, теперь у нас есть действительно хороший Q amp; A, который мы можем использовать как канонический для закрытия дубликатов.

5. @RemyLebeau Спасибо, я искал это.

Ответ №2:

Я подозреваю, что вам нужна функция, которая принимает массив байтов (или необработанный указатель на байты) и возвращает строку, содержащую данные в шестнадцатеричной форме.

Для этого я всегда использую следующую свою процедуру:

 function BytesToString(ABuf: PByte; ALen: Cardinal): string; overload;
const
  HexDigits: array[0..$F] of Char = '0123456789ABCDEF';
var
   i: Integer;
begin
   if ALen = 0 then
   begin
     Result := '';
     Exit;
   end;
   SetLength(Result, 3 * ALen - 1);
   Result[1] := HexDigits[ABuf^ shr 4];
   Result[2] := HexDigits[ABuf^ and $0F];
   for i := 1 to ALen - 1 do
   begin
     Inc(ABuf);
     Result[3*i   0] := ' ';
     Result[3*i   1] := HexDigits[ABuf^ shr 4];
     Result[3*i   2] := HexDigits[ABuf^ and $0F];
   end;
end;

type
  TByteArray = array of Byte;

function BytesToString(ABytes: TByteArray): string; overload;
begin
  Result := BytesToString(PByte(ABytes), Length(ABytes));
end;
 

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

Это очень быстрая реализация, поскольку я не использую конкатенацию строк (которая требует постоянных перераспределений кучи).


Приведенный выше код был написан специально для старого компилятора Delphi 7 и RTL. Современная версия будет выглядеть примерно так:

 function BytesToString(ABuf: PByte; ALen: Cardinal): string; overload;
const
  HexDigits: array[0..$F] of Char = '0123456789ABCDEF';
var
   i: Integer;
begin
   if ALen = 0 then
    Exit('');
   SetLength(Result, 3 * ALen - 1);
   Result[1] := HexDigits[ABuf[0] shr 4];
   Result[2] := HexDigits[ABuf[0] and $0F];
   for i := 1 to ALen - 1 do
   begin
     Result[3*i   0] := ' ';
     Result[3*i   1] := HexDigits[ABuf[i] shr 4];
     Result[3*i   2] := HexDigits[ABuf[i] and $0F];
   end;
end;

function BytesToString(ABytes: TArray<Byte>): string; overload;
begin
  Result := BytesToString(PByte(ABytes), Length(ABytes));
end;
 

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

Комментарии:

1. Честно говоря, я действительно чесал голову, когда увидел 3 * ALen … То есть, пока я не увидел пробел.

2. PByte Математика ptr на основе IIRC недоступна в Delphi 7, поэтому я заменил ее еще несколькими методами старой школы.