数据库连接设为UTF-8时,如何正确加载PostgreSQL流到TQuery.SQL?
问题:PostgreSQL UTF-8编码下FireDAC流加载大文本仅显示第一个字符
我们正在将项目的数据库连接从WIN1252改为UTF-8(基于FireDAC),PostgreSQL数据库本身采用UTF-8编码创建。部分大文本字段通过流加载,原本功能正常,但现在仅能加载文本的第一个字符。
修改前代码
procedure TfrmTeste.LoadSqlScript_old; var _Stream: TStream; begin _Stream := qry1.CreateBlobStream( qry1.FieldByName('Script'), bmRead ); try FReportQry.Sql.LoadFromStream(_Stream); finally _Stream.Free; end; end;
排查用新代码
procedure TfrmTeste.LoadSqlScript_new; var _StringStream: TStringStream; _Stream: TStream; begin _StringStream := TStringStream.Create; try _Stream := qry1.CreateBlobStream( qry1.FieldByName('Script'), bmRead ); try _StringStream.LoadFromStream(_Stream); _StringStream.SaveToFile('c:\tmp\test.sql'); FReportQry.Sql.LoadFromStream(_StringStream); finally _Stream.Free; end; finally _StringStream.Free; end; end;
奇怪的是,保存到磁盘的文本文件内容完整,但加载到TQuery.SQL的内容仅包含第一个字符。开发环境为Delphi Rio 10.3.3 + FireDAC。
问题原因与解决方案
核心原因
- 流位置未重置:新代码中
_StringStream.LoadFromStream(_Stream)执行后,流的指针已经移动到末尾,直接调用FReportQry.Sql.LoadFromStream会从当前位置(末尾)开始读取,实际读不到内容;而旧代码中二进制流直接加载时,UTF-8多字节编码被误判为单字节终止符,导致仅读取第一个ASCII字符。 - 编码未明确指定:默认
TStringStream使用系统编码(原WIN1252),与数据库UTF-8编码不匹配,导致转换异常。
解决方案1:重置流位置并指定编码
在加载到TQuery.SQL前,重置流的起始位置,并创建TStringStream时明确指定UTF-8编码:
procedure TfrmTeste.LoadSqlScript_fixed; var _StringStream: TStringStream; _Stream: TStream; begin // 明确指定UTF-8编码创建流 _StringStream := TStringStream.Create('', TEncoding.UTF8); try _Stream := qry1.CreateBlobStream(qry1.FieldByName('Script'), bmRead); try _StringStream.LoadFromStream(_Stream); _StringStream.SaveToFile('c:\tmp\test.sql'); // 重置流到起始位置 _StringStream.Position := 0; FReportQry.Sql.LoadFromStream(_StringStream); finally _Stream.Free; end; finally _StringStream.Free; end; end;
解决方案2:直接读取字段字符串(推荐)
FireDAC的TBlobField支持直接读取Unicode字符串,自动处理编码转换,无需手动操作流:
procedure TfrmTeste.LoadSqlScript_simple; begin // 直接读取字段内容,FireDAC自动处理UTF-8到Unicode的转换 FReportQry.Sql.Text := qry1.FieldByName('Script').AsString; end;
内容的提问来源于stack exchange,提问作者Leo Bruno
相关产品推荐
相关产品推荐

