You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:将TByteDynArray转字符串/TMemoryStream后PDF保存损坏,哪里出错?

问题描述

我需要把TByteDynArray类型变量的内容复制到字符串变量,或者更理想的是复制到TMemoryStream中。之前参考过Remy的解答,但实际操作时遇到问题:

obtReferenciaPagamentoResponse.pdf是通过WebService调用获取的TByteDynArray类型(XSD中定义为xsd:base64Binary),我写了下面的saveFile过程尝试保存为PDF文件,但保存后的文件始终损坏无法打开:

procedure saveFile;
var
  LInput, LOutput: TMemoryStream;
  Id: Integer;
  Buff: AnsiString;
  //Buff: String;
begin
  LInput := TMemoryStream.Create;
  LOutput := TMemoryStream.Create;

  // Tried like this also
  //SetLength(Buff, Length(obtReferenciaPagamentoResponse.pdf));
  //Move(obtReferenciaPagamentoResponse.pdf[0], Buff[1],       Length(obtReferenciaPagamentoResponse.pdf));

  // Tried other charsets
  Buff := TEncoding.Ansi.GetString(obtReferenciaPagamentoResponse.pdf);

  LInput.Write(Buff[1], Length(Buff) * SizeOf(Buff[1]));
  LInput.Position := 0;

  TNetEncoding.Base64.Decode(LInput, LOutput);
  LOutput.Position := 0;
  LOutput.SaveToFile(SaveDialog2.FileName);

  LInput.Free;
  LOutput.Free;
end;

请问我哪里操作出错了?

问题分析与修正

你的代码有两个关键错误:

  1. 多做了一次Base64解码
    WebService返回的TByteDynArray对应xsd:base64Binary时,Delphi的SOAP框架已经自动完成了Base64解码,这个数组里的内容就是PDF的原始二进制数据。你再调用TNetEncoding.Base64.Decode,相当于把已经是原始数据的内容又做了一次Base64解码,直接破坏了文件结构。

  2. 用字符串中转二进制数据错误
    二进制数据(比如PDF)不能直接用AnsiString或String中转,TEncoding.Ansi.GetString会把字节按ANSI编码规则转换成字符,这个过程会改变原始字节值,导致数据损坏。哪怕用Move直接拷贝字节到字符串,字符串的管理逻辑也可能对二进制数据造成干扰。

修正后的代码(直接保存到文件)

如果只是要保存成PDF文件,不需要用MemoryStream中转,直接操作TByteDynArray即可:

procedure saveFile;
var
  LStream: TMemoryStream;
begin
  LStream := TMemoryStream.Create;
  try
    // 直接把TByteDynArray的二进制数据写入流
    if Length(obtReferenciaPagamentoResponse.pdf) > 0 then
      LStream.WriteBuffer(obtReferenciaPagamentoResponse.pdf[0], Length(obtReferenciaPagamentoResponse.pdf));
    LStream.SaveToFile(SaveDialog2.FileName);
  finally
    LStream.Free;
  end;
end;

若需要转存到TMemoryStream

如果确实需要把TByteDynArray复制到TMemoryStream,代码可以更简洁:

procedure CopyByteDynArrayToStream(const AArray: TByteDynArray; AStream: TStream);
begin
  if (AStream <> nil) and (Length(AArray) > 0) then
    AStream.WriteBuffer(AArray[0], Length(AArray));
end;

// 调用示例:
var
  LStream: TMemoryStream;
begin
  LStream := TMemoryStream.Create;
  try
    CopyByteDynArrayToStream(obtReferenciaPagamentoResponse.pdf, LStream);
    LStream.Position := 0;
    // 这里可以对LStream做后续操作,比如保存文件、传输等
    LStream.SaveToFile(SaveDialog2.FileName);
  finally
    LStream.Free;
  end;
end;

内容的提问来源于stack exchange,提问作者Carlos Matos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 15:50:29