Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 从JSON文件解码UTF-8_Delphi_Firemonkey - Fatal编程技术网

Delphi 从JSON文件解码UTF-8

Delphi 从JSON文件解码UTF-8,delphi,firemonkey,Delphi,Firemonkey,我有一个JSON文件,其中包含一个表示JPG内容的编码UTF-8字符串字段: “图像数据”:“u0000\u0010JFIF\u0000\u0001\u0002\u0000\u0000d\u0000d\u0000\u0000\u0000” 我正在解析JSON并获取该值: var-imageString:string; ... imageString:=jv.GetValue('ImageData'); 但我在解码字节并将其保存到文件时遇到问题 选项1.SaveBytesToFile(Byte

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

“图像数据”:“u0000\u0010JFIF\u0000\u0001\u0002\u0000\u0000d\u0000d\u0000\u0000\u0000”
我正在解析JSON并获取该值:

var-imageString:string;
...
imageString:=jv.GetValue('ImageData');
但我在解码字节并将其保存到文件时遇到问题

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

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

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

与备选方案1类似的问题

SaveBytesToFile的代码:

过程SaveBytesToFile(常量数据:TBytes;常量文件名:string);
变量
流:TMemoryStream;
开始
stream:=TMemoryStream.Create;
尝试
如果长度(数据)>0,则
stream.WriteBuffer(数据[0],长度(数据));
stream.SaveToFile(文件名);
最后
免费;
结束;
结束;

如何正确解码?

JSON是一种纯文本格式,它根本没有处理二进制数据的规定。为什么图像字节没有以文本兼容的格式编码,如、、等?否则,请使用(二进制JSON)或(通用二进制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;
或:

或:


JSON是一种纯文本格式,它根本没有处理二进制数据的规定。为什么图像字节没有以文本兼容的格式编码,如、、等?否则,请使用(二进制JSON)或(通用二进制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;
或:

或:


C3 BF C3 98 C3 BF C3 A0
是UTF-8字符串
的正确字节,我认为您的选项1转换是有效的

不要被你的十六进制编辑器所愚弄:UTF-8字符都不在ASCII范围内,但是十六进制编辑器通常为每个字节显示e-ASCII字符,这就是为什么它显示的是
字符而不是
字符


请检查@RemyLebeau提到的区域设置问题,我认为使用TEncoding.ASCII是正确的。

C3 BF C3 98 C3 BF C3 A0
是UTF-8字符串
的正确字节,我认为您的选项1转换工作正常

不要被你的十六进制编辑器所愚弄:UTF-8字符都不在ASCII范围内,但是十六进制编辑器通常为每个字节显示e-ASCII字符,这就是为什么它显示的是
字符而不是
字符


请务必检查@RemyLebeau提到的区域设置问题,我认为使用TEncoding.ASCII是正确的。

谢谢您的帮助。遗憾的是,我无法控制生成的JSON,因此我需要使用它。我已经实现了您建议的代码,但我得到了相同的结果。顺便说一句,我注意到,在从JSON读取值后e已经是一些数据丢失,即“数据丢失”在这个屏幕截图中,实际上只是原始的UTF-8字节八位字节被存储为字符串。您使用的是什么版本的Delphi,您使用的是哪个JSON库?您是否告诉库将JSON文件解码为UTF-8?如果不是,你应该是。如果是,它不应该将原始UTF-8八位字节作为字符串输出,除非您使用的是Delphi2007或更早版本。但是在Delphi 2009中,
string
UnicodeString
,原始UTF-8八位字节不应该输出到Unicode字符串中。我没有用TEncoding.UTF8将JSON读取为UTF-8。谢谢。类似于Base64,其中一组字符编码二进制值,我称之为Base256。它比Base64更紧凑,但只能在支持256个不同字符时使用。通常编码与ISO 8859-1相反。(即使这样正式表达,我还是不喜欢。)谢谢你的帮助。遗憾的是,我无法控制生成的JSON,因此需要使用它。我已经实现了你建议的代码,但是我得到了相同的结果,顺便说一句,我注意到在从json读取值之后,已经有一些数据丢失,屏幕截图中的“数据丢失”实际上只是原始UTF-8字节八位字节被存储为字符串。您使用的是什么版本的Delphi,您使用的是哪个JSON库?您是否告诉库将JSON文件解码为UTF-8?如果不是,你应该是。如果是,它不应该将原始UTF-8八位字节作为字符串输出,除非您使用的是Delphi2007或更早版本。但是在Delphi2009中,
string
unicodesti
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;