You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

数据库连接设为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。


问题原因与解决方案

核心原因

  1. 流位置未重置:新代码中_StringStream.LoadFromStream(_Stream)执行后,流的指针已经移动到末尾,直接调用FReportQry.Sql.LoadFromStream会从当前位置(末尾)开始读取,实际读不到内容;而旧代码中二进制流直接加载时,UTF-8多字节编码被误判为单字节终止符,导致仅读取第一个ASCII字符。
  2. 编码未明确指定:默认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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 09:10:07