从 JSON 文件解码 UTF-8
Decode UTF-8 from JSON file
我有一个 JSON 文件,其中包含代表 JPG 内容的编码 UTF-8 字符串字段:
"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);
如您所见,header 不正确(应以 ÿØÿà 开头)
选项 2。SaveBytesToFile(TEncoding.UTF8.GetBytes(imageString),pathFile);
与选项 1 类似的问题
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;
如何正确解码?
JSON 是一种纯文本格式,它根本没有处理二进制数据的规定。为什么图像字节没有以文本兼容格式编码,例如 base64, base85, base91, etc? Otherwise, use something like BSON (Binary JSON) or 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;
附带说明一下,您的 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;
C3 BF C3 98 C3 BF C3 A0
是 UTF-8 字符串 ÿØÿà
的正确字节,我认为您的选项 1 转换有效。
不要被您的十六进制编辑器所愚弄:UTF-8 字符 ÿØÿà
都在 ASCII 范围之外,但是十六进制编辑器通常会为每个字节显示 e-ASCII 字符,这就是为什么它显示 ÿ
而不是 ÿ
.
请检查@RemyLebeau 提到的区域设置问题,我认为使用 TEncoding.ASCII 是正确的。
我有一个 JSON 文件,其中包含代表 JPG 内容的编码 UTF-8 字符串字段:
"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);
如您所见,header 不正确(应以 ÿØÿà 开头)
选项 2。SaveBytesToFile(TEncoding.UTF8.GetBytes(imageString),pathFile);
与选项 1 类似的问题
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;
如何正确解码?
JSON 是一种纯文本格式,它根本没有处理二进制数据的规定。为什么图像字节没有以文本兼容格式编码,例如 base64, base85, base91, etc? Otherwise, use something like BSON (Binary JSON) or 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;
附带说明一下,您的 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;
C3 BF C3 98 C3 BF C3 A0
是 UTF-8 字符串 ÿØÿà
的正确字节,我认为您的选项 1 转换有效。
不要被您的十六进制编辑器所愚弄:UTF-8 字符 ÿØÿà
都在 ASCII 范围之外,但是十六进制编辑器通常会为每个字节显示 e-ASCII 字符,这就是为什么它显示 ÿ
而不是 ÿ
.
请检查@RemyLebeau 提到的区域设置问题,我认为使用 TEncoding.ASCII 是正确的。