[英]How can I get a regular Delphi string from a stream after retrieving an object from Amazon S3?
I am putting a JSON string into Amazon S3 using the TAmazonStorageService class UploadObject method.我正在使用 TAmazonStorageService class UploadObject 方法将 JSON 字符串放入 Amazon S3。 When I retrieve the object it is placed in a stream (I am using a TStringStream), which appears to be coded in UTF-16 LE.
当我检索 object 时,它被放置在 stream(我使用的是 TStringStream)中,它似乎是用 UTF-16 LE 编码的。 If I then attempt to load that JSON into a memo, a TStringList, or any other similar object I get just the first character, the open curly brace of the JSON.
然后,如果我尝试将该 JSON 加载到备忘录、TStringList 或任何其他类似的 object 中,我只会得到第一个字符,即 Z0ECD11C1D7A287401D148A23BBD7A2F8 的开放花括号。 On the other hand, if I write it to a file I get the entire JSON (UTF-16 LE encoded).
另一方面,如果我将它写入一个文件,我会得到整个 JSON(UTF-16 LE 编码)。 I am assuming that because UTF-16 LE encodes each character with two bytes, and the second byte is always 0, Delphi is assuming that the 0 is the end of file marker.
我假设因为 UTF-16 LE 用两个字节对每个字符进行编码,并且第二个字节始终为 0,所以 Delphi 假设 0 是文件结束标记。
How can I get a regular Delphi string (WideString), or even an ANSIString from the TStringStream, or is there another stream that I should use that I can use to get a WideString or ANSIString.如何从 TStringStream 中获取常规的 Delphi 字符串(WideString),甚至是 ANSIString,或者是否有另一个 stream 可以用来获取 WideString 或 ANSIString。
Here is pseudo code that represents the upload:这是代表上传的伪代码:
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;
And here is pseudo code that represents the retrieval of the JSON:这是代表检索 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;
In Delphi 2009 and later, String
is a UTF-16 UnicodeString
, however TStringStream
operates on 8-bit ANSI by default (for backwards compatibility with pre-Unicode Delphi versions).在 Delphi 2009 及更高版本中,
String
是 UTF-16 UnicodeString
,但是TStringStream
默认在 8 位 ANSI 上运行(为了向后兼容 Unicode 之前的 Delphi 版本)。
There is no need for StorePayload()
to use TStringStream
at all. StorePayload()
根本不需要使用TStringStream
。 You are storing a String
into the stream just to read a String
back out from it.您将
String
存储到 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 中只是为了从中读取String
。 So just use the original String
as-is.所以只需按原样使用原始
String
。
Using StringToBytes()
is unnecessary, too.也不需要使用
StringToBytes()
。 You can, and should, use TEncoding.UTF8
instead, as UTF-8 is the preferred encoding for JSON data, eg:您可以并且应该使用
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;
Conversely, when RetrievePayload()
calls GetObject()
later, you can use TEncoding.UTF8
with TStringStream
to decode the String
, eg:相反,当
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;
If you need to retrieve any pre-existing bucket objects that have already been uploaded as UTF-16, RetrievePayload()
could use TEncoding.Unicode
instead:如果您需要检索已上传为 UTF-16 的任何预先存在的存储桶对象,
RetrievePayload()
可以使用TEncoding.Unicode
代替:
ss := TStringStream.Create( '', TEncoding.Unicode );
However, that won't work for newer objects uploaded with UTF-8.但是,这不适用于使用 UTF-8 上传的较新对象。 So, a more flexible solution would be to retrieve the raw bytes using a
TMemoryStream
or TBytesStream
, then analyze the bytes to determine whether UTF8 or UTF-16 were used, and then use TEncoding.UTF8.GetString()
or TEncoding.Unicode.GetString()
to decode the bytes to a String
.因此,更灵活的解决方案是使用
TMemoryStream
或TBytesStream
检索原始字节,然后分析字节以确定是否使用了 UTF8 或 UTF-16,然后使用TEncoding.UTF8.GetString()
或TEncoding.Unicode.GetString()
将字节解码为String
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.