Delphi 从JSON文件解码UTF-8
我有一个JSON文件,其中包含一个表示JPG内容的编码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
“图像数据”:“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;