从 Amazon S3 检索对象后,如何从流中获取常规 Delphi 字符串?
How can I get a regular Delphi string from a stream after retrieving an object from Amazon S3?
我正在使用 TAmazonStorageService class UploadObject 方法将 JSON 字符串放入 Amazon S3。当我检索对象时,它被放置在一个流中(我使用的是 TStringStream),它似乎是用 UTF-16 LE 编码的。如果我随后尝试将 JSON 加载到备忘录、TStringList 或任何其他类似对象中,我只会得到第一个字符,即 JSON 的左大括号。另一方面,如果我将它写入文件,我会得到整个 JSON (UTF-16 LE 编码)。我假设因为 UTF-16 LE 用两个字节对每个字符进行编码,并且第二个字节始终为 0,所以 Delphi 假设 0 是文件标记的结尾。
如何从 TStringStream 中获取常规 Delphi 字符串 (WideString) 或什至 ANSIString,或者是否有我应该使用的另一个流,我可以使用它来获取 WideString 或 ANSIString。
这是代表上传的伪代码:
procedure StorePayload( AmazonConnectionInfo: TAmazonConnectionInfo; JSONString: String;
PayloadMemTable: TFDAdaptedDataSet;
PayloadType: String; PayloadVersion: Integer);
var
AmazonStorageService: TAmazonStorageService;
ab: TBytes;
ResponseInfo: TCloudResponseInfo;
ss: TStringStream;
Guid: TGuid;
begin
Guid := TGuid.NewGuid;
AmazonStorageService := TAmazonStorageService.Create( AmazonConnectionInfo );
try
// Write payload to S3
ResponseInfo := TCloudResponseInfo.Create;
try
ss := TStringStream.Create( JSONString );
try
ab := StringToBytes( ss.DataString );
if AmazonStorageService.UploadObject( BucketName, Guid.ToString, ab, false, nil, nil, amzbaPrivate, ResponseInfo ) then
PayloadMemTable.AppendRecord( [Guid.ToString, PayloadType, PayloadVersion, now() ] );
finally
ss.Free;
end;
finally
ResponseInfo.Free;
end;
finally
AmazonStorageService.Free;
end;
end;
这里是表示检索 JSON:
的伪代码
function RetrievePayload( AmazonConnectionInfo: TAmazonConnectionInfo ): String;
var
AmazonStorageService: TAmazonStorageService;
ObjectName: string;
ResponseInfo: TCloudResponseInfo;
ss: TStringStream;
OptParams: TAmazonGetObjectOptionals;
begin
// I tried with and without the TAmazonGetObjectOptionals
OptParams := TAmazonGetObjectOptionals.Create;
OptParams.ResponseContentEncoding := 'ANSI';
OptParams.ResponseContentType := 'text/plain';
AmazonStorageService := TAmazonStorageService.Create( AmazonConnectionInfo );
try
ss := TStringStream.Create( );
try
ResponseInfo := TCloudResponseInfo.Create;
try
if not AmazonStorageService.GetObject( BucketName, PayloadID, OptParams,
ss, ResponseInfo, amzrNotSpecified ) then
raise Exception.Create('Error retrieving item ' + ObjectName);
Result := ss.DataString;
// The memo will contain only {
Form1.Memo1.Lines.Text := ss.DataString;
finally
ResponseInfo.Free;
end;
finally
ss.Free;
end;
finally
AmazonStorageService.Free;
end;
end;
在 Delphi 2009 及之后的版本中,String
是 UTF-16 UnicodeString
,但是 TStringStream
默认在 8 位 ANSI 上运行(为了向后兼容前 Unicode Delphi 版本)。
StorePayload()
根本没必要用TStringStream
。您将 String
存储到流中只是为了从中读取 String
。所以只需按原样使用原始 String
。
也不需要使用StringToBytes()
。您可以而且应该改用 TEncoding.UTF8
,因为 UTF-8 是 JSON 数据的首选编码,例如:
procedure StorePayload( AmazonConnectionInfo: TAmazonConnectionInfo; JSONString: String;
PayloadMemTable: TFDAdaptedDataSet;
PayloadType: String; PayloadVersion: Integer);
var
AmazonStorageService: TAmazonStorageService;
ab: TBytes;
ResponseInfo: TCloudResponseInfo;
Guid: TGuid;
begin
Guid := TGuid.NewGuid;
AmazonStorageService := TAmazonStorageService.Create( AmazonConnectionInfo );
try
// Write payload to S3
ResponseInfo := TCloudResponseInfo.Create;
try
ab := TEncoding.UTF8.GetBytes( JSONString );
if AmazonStorageService.UploadObject( BucketName, Guid.ToString, ab, false, nil, nil, amzbaPrivate, ResponseInfo ) then
PayloadMemTable.AppendRecord( [Guid.ToString, PayloadType, PayloadVersion, Now() ] );
finally
ResponseInfo.Free;
end;
finally
AmazonStorageService.Free;
end;
end;
反之,当RetrievePayload()
稍后调用GetObject()
时,可以用TEncoding.UTF8
配合TStringStream
解码String
,如:
function RetrievePayload( AmazonConnectionInfo: TAmazonConnectionInfo ): String;
var
AmazonStorageService: TAmazonStorageService;
ResponseInfo: TCloudResponseInfo;
ss: TStringStream;
begin
AmazonStorageService := TAmazonStorageService.Create( AmazonConnectionInfo );
try
ss := TStringStream.Create( '', TEncoding.UTF8 );
try
ResponseInfo := TCloudResponseInfo.Create;
try
if not AmazonStorageService.GetObject( BucketName, PayloadID, ss, ResponseInfo, amzrNotSpecified ) then
raise Exception.Create('Error retrieving item ' + ObjectName);
Result := ss.DataString;
Form1.Memo1.Text := Result;
finally
ResponseInfo.Free;
end;
finally
ss.Free;
end;
finally
AmazonStorageService.Free;
end;
end;
如果您需要检索任何已作为 UTF-16 上传的预先存在的存储桶对象,RetrievePayload()
可以改用 TEncoding.Unicode
:
ss := TStringStream.Create( '', TEncoding.Unicode );
但是,这不适用于使用 UTF-8 上传的较新对象。因此,更灵活的解决方案是使用 TMemoryStream
或 TBytesStream
检索原始字节,然后分析字节以确定使用的是 UTF8 还是 UTF-16,然后使用 TEncoding.UTF8.GetString()
或 TEncoding.Unicode.GetString()
将字节解码为 String
.
我正在使用 TAmazonStorageService class UploadObject 方法将 JSON 字符串放入 Amazon S3。当我检索对象时,它被放置在一个流中(我使用的是 TStringStream),它似乎是用 UTF-16 LE 编码的。如果我随后尝试将 JSON 加载到备忘录、TStringList 或任何其他类似对象中,我只会得到第一个字符,即 JSON 的左大括号。另一方面,如果我将它写入文件,我会得到整个 JSON (UTF-16 LE 编码)。我假设因为 UTF-16 LE 用两个字节对每个字符进行编码,并且第二个字节始终为 0,所以 Delphi 假设 0 是文件标记的结尾。
如何从 TStringStream 中获取常规 Delphi 字符串 (WideString) 或什至 ANSIString,或者是否有我应该使用的另一个流,我可以使用它来获取 WideString 或 ANSIString。
这是代表上传的伪代码:
procedure StorePayload( AmazonConnectionInfo: TAmazonConnectionInfo; JSONString: String;
PayloadMemTable: TFDAdaptedDataSet;
PayloadType: String; PayloadVersion: Integer);
var
AmazonStorageService: TAmazonStorageService;
ab: TBytes;
ResponseInfo: TCloudResponseInfo;
ss: TStringStream;
Guid: TGuid;
begin
Guid := TGuid.NewGuid;
AmazonStorageService := TAmazonStorageService.Create( AmazonConnectionInfo );
try
// Write payload to S3
ResponseInfo := TCloudResponseInfo.Create;
try
ss := TStringStream.Create( JSONString );
try
ab := StringToBytes( ss.DataString );
if AmazonStorageService.UploadObject( BucketName, Guid.ToString, ab, false, nil, nil, amzbaPrivate, ResponseInfo ) then
PayloadMemTable.AppendRecord( [Guid.ToString, PayloadType, PayloadVersion, now() ] );
finally
ss.Free;
end;
finally
ResponseInfo.Free;
end;
finally
AmazonStorageService.Free;
end;
end;
这里是表示检索 JSON:
的伪代码function RetrievePayload( AmazonConnectionInfo: TAmazonConnectionInfo ): String;
var
AmazonStorageService: TAmazonStorageService;
ObjectName: string;
ResponseInfo: TCloudResponseInfo;
ss: TStringStream;
OptParams: TAmazonGetObjectOptionals;
begin
// I tried with and without the TAmazonGetObjectOptionals
OptParams := TAmazonGetObjectOptionals.Create;
OptParams.ResponseContentEncoding := 'ANSI';
OptParams.ResponseContentType := 'text/plain';
AmazonStorageService := TAmazonStorageService.Create( AmazonConnectionInfo );
try
ss := TStringStream.Create( );
try
ResponseInfo := TCloudResponseInfo.Create;
try
if not AmazonStorageService.GetObject( BucketName, PayloadID, OptParams,
ss, ResponseInfo, amzrNotSpecified ) then
raise Exception.Create('Error retrieving item ' + ObjectName);
Result := ss.DataString;
// The memo will contain only {
Form1.Memo1.Lines.Text := ss.DataString;
finally
ResponseInfo.Free;
end;
finally
ss.Free;
end;
finally
AmazonStorageService.Free;
end;
end;
在 Delphi 2009 及之后的版本中,String
是 UTF-16 UnicodeString
,但是 TStringStream
默认在 8 位 ANSI 上运行(为了向后兼容前 Unicode Delphi 版本)。
StorePayload()
根本没必要用TStringStream
。您将 String
存储到流中只是为了从中读取 String
。所以只需按原样使用原始 String
。
也不需要使用StringToBytes()
。您可以而且应该改用 TEncoding.UTF8
,因为 UTF-8 是 JSON 数据的首选编码,例如:
procedure StorePayload( AmazonConnectionInfo: TAmazonConnectionInfo; JSONString: String;
PayloadMemTable: TFDAdaptedDataSet;
PayloadType: String; PayloadVersion: Integer);
var
AmazonStorageService: TAmazonStorageService;
ab: TBytes;
ResponseInfo: TCloudResponseInfo;
Guid: TGuid;
begin
Guid := TGuid.NewGuid;
AmazonStorageService := TAmazonStorageService.Create( AmazonConnectionInfo );
try
// Write payload to S3
ResponseInfo := TCloudResponseInfo.Create;
try
ab := TEncoding.UTF8.GetBytes( JSONString );
if AmazonStorageService.UploadObject( BucketName, Guid.ToString, ab, false, nil, nil, amzbaPrivate, ResponseInfo ) then
PayloadMemTable.AppendRecord( [Guid.ToString, PayloadType, PayloadVersion, Now() ] );
finally
ResponseInfo.Free;
end;
finally
AmazonStorageService.Free;
end;
end;
反之,当RetrievePayload()
稍后调用GetObject()
时,可以用TEncoding.UTF8
配合TStringStream
解码String
,如:
function RetrievePayload( AmazonConnectionInfo: TAmazonConnectionInfo ): String;
var
AmazonStorageService: TAmazonStorageService;
ResponseInfo: TCloudResponseInfo;
ss: TStringStream;
begin
AmazonStorageService := TAmazonStorageService.Create( AmazonConnectionInfo );
try
ss := TStringStream.Create( '', TEncoding.UTF8 );
try
ResponseInfo := TCloudResponseInfo.Create;
try
if not AmazonStorageService.GetObject( BucketName, PayloadID, ss, ResponseInfo, amzrNotSpecified ) then
raise Exception.Create('Error retrieving item ' + ObjectName);
Result := ss.DataString;
Form1.Memo1.Text := Result;
finally
ResponseInfo.Free;
end;
finally
ss.Free;
end;
finally
AmazonStorageService.Free;
end;
end;
如果您需要检索任何已作为 UTF-16 上传的预先存在的存储桶对象,RetrievePayload()
可以改用 TEncoding.Unicode
:
ss := TStringStream.Create( '', TEncoding.Unicode );
但是,这不适用于使用 UTF-8 上传的较新对象。因此,更灵活的解决方案是使用 TMemoryStream
或 TBytesStream
检索原始字节,然后分析字节以确定使用的是 UTF8 还是 UTF-16,然后使用 TEncoding.UTF8.GetString()
或 TEncoding.Unicode.GetString()
将字节解码为 String
.