从JSON文件解码UTF-8

时间:2019-04-16 19:49:11

标签: delphi firemonkey

我有一个JSON文件,其编码的UTF-8字符串字段表示JPG内容:

"ImageData": "ÿØÿà\u0000\u0010JFIF\u0000\u0001\u0002\u0000\u0000d\u0000d\u0000\u0000

我正在解析JSON并获取该值:

var imageString : string;
...
imageString:=jv.GetValue<string>('ImageData');

但是我在解码字节并将它们保存到文件时遇到了问题

选项1。SaveBytesToFile(BytesOf(imageString),pathFile);

如您所见,标题不正确(应以ÿØÿà开头)

option1

选项2。SaveBytesToFile(TEncoding.UTF8.GetBytes(imageString),pathFile);

类似的问题作为选项1

option2

SaveBytesToFile的代码:

procedure SaveBytesToFile(const Data: TBytes; const FileName: string);
var
  stream: TMemoryStream;
begin
  stream := TMemoryStream.Create;
  try
    if length(data) > 0 then
      stream.WriteBuffer(data[0], length(data));
    stream.SaveToFile(FileName);
  finally
    stream.Free;
  end;
end;

如何正确解码?

2 个答案:

答案 0 :(得分:10)

JSON是纯文本格式,根本没有提供处理二进制数据的规定。为什么图像字节没有以文本兼容格式编码,例如base64base85base91等?否则,请改用BSON(二进制JSON)或UBJSON(通用二进制JSON)之类的东西,它们都支持二进制数据。

在任何情况下,BytesOf()都会破坏字节,因为它使用用户的默认语言环境(通过TEncoding.Default,在非Windows平台上为UTF-8!),因此ASCII之外的字符范围受语言环境的解释,不会产生所需的字节。

根据您的情况,确保JSON库将JSON文件解码为UTF-8,然后您可以简单地遍历结果字符串(JSON库应为您将转义的序列解析为字符)并截断字符原样为8位值。根本不执行任何类型的字符集转换。例如:

var
  imageString : string;
  imageBytes: TBytes;
  i: Integer;
  ...
begin
  ...

  imageString := jv.GetValue<string>('ImageData');

  SetLength(imageBytes, Length(imageString));
  for i := 0 to Length(imageString)-1 do begin
    imageBytes[i] := Byte(imageString[i+1]);
  end;

  SaveBytesToFile(imageBytes, pathFile);

  ...
end;

image

请注意,您的SaveBytesToFile()可以大大简化,而不会浪费内存复制TBytes

procedure SaveBytesToFile(const Data: TBytes; const FileName: string);
var
  stream: TBytesStream;
begin
  stream := TBytesStream.Create(Data);
  try
    stream.SaveToFile(FileName);
  finally
    stream.Free;
  end;
end;

或者:

procedure SaveBytesToFile(const Data: TBytes; const FileName: string);
var
  stream: TFileStream;
begin
  stream := TFileStream.Create(FileName, fmCreate);
  try
    stream.WriteBuffer(PByte(Data)^, Length(Data));
  finally
    stream.Free;
  end;
end;

或者:

uses
  ..., System.IOUtils;

procedure SaveBytesToFile(const Data: TBytes; const FileName: string);
begin
  System.IOUtils.TFile.WriteAllBytes(FileName, Data);
end;

答案 1 :(得分:0)

C3 BF C3 98 C3 BF C3 A0是UTF-8字符串ÿØÿà的正确字节,我想说您的Option 1转换有效。

不要被十六进制编辑器所欺骗:UTF-8字符ÿØÿà均不在ASCII范围内,但是十六进制编辑器通常为每个字节显示e-ASCII字符,这就是为什么它显示ÿ而不是ÿ

请检查@RemyLebeau提到的语言环境问题,我认为使用TEncoding.ASCII是正确的