使用delphi 2007进行base64编码和解码base64

问题描述 投票:0回答:6

我必须在旧的 Delphi 2007 上将字节数组编码为 Base64 字符串(并解码该字符串)。 我该怎么办?

更多信息:

我尝试过突触(如此处建议的二进制到Base64(Delphi))。

delphi encoding base64 decoding delphi-2007
6个回答
11
投票

Indy 随 Delphi 一起提供,并具有用于处理 base64 的

TIdEncoderMIME
TIdDecoderMIME
类。 例如:

uses
  ..., IdCoder, IdCoderMIME;

var
  Bytes: TIdBytes;
  Base64String: String;
begin
  //...
  Bytes := ...; // array of bytes
  //...
  Base64String := TIdEncoderMIME.EncodeBytes(Bytes);
  //...
  Bytes := TIdDecoderMIME.DecodeBytes(Base64String);
  //...
end;

还有编码/解码

String
TStream
数据的方法。

更新:或者,如果您的版本没有上面显示的

class
方法:

// TBytesStream was added in D2009, so define it manually for D2007

uses
  ..., IdCoder, IdCoderMIME
  {$IF RTLVersion < 20}
  , RTLConsts
  {$IFEND}
  ;

{$IF RTLVersion < 20}
type
  TBytesStream = class(TMemoryStream)
  private
    FBytes: TBytes;
  protected
    function Realloc(var NewCapacity: Longint): Pointer; override;
  public
    constructor Create(const ABytes: TBytes); overload;
    property Bytes: TBytes read FBytes;
  end;

constructor TBytesStream.Create(const ABytes: TBytes);
begin
  inherited Create;
  FBytes := ABytes;
  SetPointer(Pointer(FBytes), Length(FBytes));
  FCapacity := FSize;
end;

const
  MemoryDelta = $2000; // Must be a power of 2

function TBytesStream.Realloc(var NewCapacity: Integer): Pointer;
begin
  if (NewCapacity > 0) and (NewCapacity <> FSize) then
    NewCapacity := (NewCapacity + (MemoryDelta - 1)) and not (MemoryDelta - 1);
  Result := Pointer(FBytes);
  if NewCapacity <> FCapacity then
  begin
    SetLength(FBytes, NewCapacity);
    Result := Pointer(FBytes);
    if NewCapacity = 0 then
      Exit;
    if Result = nil then raise EStreamError.CreateRes(@SMemoryStreamError);
  end;
end;
{$IFEND}

var
  Bytes: TBytes;
  BStrm: TBytesStream;
  Encoder: TIdEncoderMIME;
  Decoder: TIdDecoderMIME;
  Base64String: String;
begin
  //...
  Bytes := ...; // array of bytes
  //...
  BStrm := TBytesStream.Create(Bytes);
  try
    Encoder := TIdEncoderMIME.Create;
    try
      Base64String := Encoder.Encode(BStrm);
    finally
      Encoder.Free;
    end;
  finally
    BStrm.Free;
  end;
  //...
  BStrm := TBytesStream.Create;
  try
    Decoder := TIdDecoderMIME.Create;
    try
      Decoder.DecodeBegin(BStrm);
      Decoder.Decode(Base64String);
      Decoder.DecodeEnd;
    finally
      Decoder.Free;
    end;
    Bytes := BStrm.Bytes;
  finally
    BStrm.Free;
  end;
  //...
end;

7
投票

与您在问题中所述相反,

EncdDecd
单元包含在Delphi 2007中。您可以简单地使用它。


5
投票

David Heffernan 反应非常好!

在你的使用类中添加“EncdDecd”,它将有程序:

function DecodeString (const Input: string): string;
function DecodeBase64 (const Input: string): TBytes;

使用 https://www.base64encode.org/

进行测试

Delphi 和网站中的字符串“Working”导致:“V29ya2luZw ==”

ShowMessage ('Working =' + EncodeString ('Working'));
ShowMessage ('Working =' + DecodeString ('V29ya2luZw =='));

1
投票

这里是 EncodeToBase64:

uses
classes, sysutils;

function EncodeToBase64(var Buffer: TBytes): Longint;
const
  EncodingTable: PChar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var
  WriteBuf: array[0..3] of Byte;
  Buf: array[0..2] of Byte;
  Dest: TMemoryStream;
  i, j, Count: Integer;
begin
  Result := 0;

  Count := Length(Buffer);
  j := Count div 3;

  if j > 0 then
  begin
    Dest:= TMemoryStream.Create();  
    try
      Dest.Position := 0;
      for i := 0 to j - 1  do
      begin
        Move(Buffer[i * 3], Buf[0], 3); 
        WriteBuf[0] := Ord(EncodingTable[Buf[0] shr 2]);
        WriteBuf[1] := Ord(EncodingTable[(Buf[0] and 3) shl 4 or (Buf[1] shr 4)]);
        WriteBuf[2] := Ord(EncodingTable[(Buf[1] and 15) shl 2 or (Buf[2] shr 6)]);
        WriteBuf[3] := Ord(EncodingTable[Buf[2] and 63]);  
        Dest.Write(WriteBuf, 4);  
        Inc(Result, 4);
        Dec(Count, 3);    
      end;          

      if Count in [1, 2] then  
      begin           
        Move(Buffer[i * 3], Buf[0], Count);
        WriteBuf[0] := Ord(EncodingTable[Buf[0] shr 2]);
        WriteBuf[1] := Ord(EncodingTable[(Buf[0] and 3) shl 4 or (Buf[1] shr 4)]); 
        if Count = 1 then
          WriteBuf[2] := Ord('=')
        else                                           
          WriteBuf[2] := Ord(EncodingTable[(Buf[1] and 15) shl 2 or (Buf[2] shr 6)]);
        WriteBuf[3] := Ord('='); 
        Dest.Write(WriteBuf, 4);  
        Inc(Result, 4);
        Dec(Count, Count);
      end;

      if Result > 0 then
      begin
        SetLength(Buffer, Result);
        Dest.Position := 0;
        Dest.Read(Buffer[0], Result);   
      end;  
    finally
      Dest.Free;
    end;
  end;

end; 

这应该无需任何特殊单元或组件即可工作。


1
投票

对于旧版本的 Delphi(Delphi XE7 之前的版本),请使用:

uses 
Soap.EncdDecd
procedure DecodeFile(const Base64: AnsiString; const FileName: string);
var
  BStream: TBytesStream;
begin
  BStream := TBytesStream.Create(DecodeBase64(Base64));
  try
    BStream.SaveToFile(Filename);
  finally
    BStream.Free;
  end;
end;

对于 Delphi 的 NEWS 版本,请使用:

uses
System.NetEncoding;
procedure DecodeFile(const Base64: String; const FileName: string);
var
  BStream: TBytesStream;
begin
  BStream:= TBytesStream.Create(TNetEncoding.Base64.DecodeStringToBytes(Base64));
  try
    BStream.SaveToFile(Filename);
  finally
    BStream.Free;
  end;
end;

0
投票

Remy Lebeau 给出的 TBytesStream 类不稳定,不会被编译。

即使编译器指令 {$IF RTLVersion < 20) 写错了,编译器指令也是以“{”开头,以“}”结尾,而不是“)”!

这是我的代码,在IDE中检查并可以编译。

unit BytesStream;
// My Github Repository <https://github.com/valient-newman>
// CompilerVersion is 18.5 for Delphi 2007 Win32

interface

{$IF CompilerVersion = 18.5}
uses
   Classes, SysUtils, RTLConsts;
{$IFEND}

// This code was taken from unit System.Classes of Delphi 10.4.2 and remade
{$IF CompilerVersion = 18.5}
type
  TBytesStream = class(TMemoryStream)
  private
    FBytes: TBytes;
    FCapacity: Longint;
    FSize: Longint;
  protected
    function Realloc(var NewCapacity: Longint): Pointer; override;
  public
    constructor Create(const ABytes: TBytes); overload;
    property Bytes: TBytes read FBytes;
  end;
{$IFEND}

implementation
{$IF CompilerVersion = 18.5}
const
  MemoryDelta = $2000; // Must be a power of 2
{$IFEND}

// This code was taken from unit System.Classes of Delphi 10.4.2
{$IF CompilerVersion = 18.5}
constructor TBytesStream.Create(const ABytes: TBytes);
begin
  inherited Create;
  FBytes := ABytes;
  SetPointer(Pointer(FBytes), Length(FBytes));
  FCapacity := FSize;
end;

function TBytesStream.Realloc(var NewCapacity: Integer): Pointer;
begin
  if (NewCapacity > 0) and (NewCapacity <> FSize) then
    NewCapacity := (NewCapacity + (MemoryDelta - 1)) and not (MemoryDelta - 1);
  Result := Pointer(FBytes);
  if NewCapacity <> FCapacity then
  begin
    SetLength(FBytes, NewCapacity);
    Result := Pointer(FBytes);
    if NewCapacity = 0 then
      Exit;
    if Result = nil then raise EStreamError.CreateRes(@SMemoryStreamError);
  end;
end;
{$IFEND}

end.
© www.soinside.com 2019 - 2024. All rights reserved.