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

使用ADO操作SQL Server空间数据时出现字符集异常问题

Delphi 10.4读取SQL Server空间字段(geometry)乱码问题解决

问题场景

使用Delphi 10.4结合ADO操作SQL Server数据库,读取包含geometry类型的空间字段时出现异常:两次读取同一数据库的同一数据,普通varchar字段(如Name)始终正常,但Geom字段一次返回正确的WKT格式字符串,另一次返回乱码字符(类似二进制字节错误转成字符串的结果)。

相关代码片段

type TDatabaserecord = record 
          ...
          NameStr : String;
          OutLineStr : String;
          ...
     end;
type TTabRecordList = class(TList<TDatabaserecord>)
     private
     ...
     public
     procedure SavetoFile(Filename: String);
     end;

procedure ReadDBConent ( ....., MYDatabaserecord : TDatabaserecord );
begin
     ....
     MyDatabaserecord.NameStr := Fieldbyname('Name').AsString;
     MyDatabaserecord.OutLineStr := Fieldbyname('Geom').AsString;
     ...
end;

procedure  TTabRecordList.SaveDBConent ( ..... );
var
  i: Integer;
  ds: TDatabaserecord;
  Content: TStringlist;
begin
  Content := TStringlist.create;
  try
    for i := 0 to self.Count - 1 do
    begin
      ds := self.Items[i];
      ...
      Content.add('Name=' + ds.NameStr);
      Content.add('OutLine=' + ds.OutLineStr);
    end;
    Content.SavetoFile(Filename);
  finally
    Content.Free;
  end;
end;

错误现象对比

正常读取结果:

Name=NameofObject    
OutLine=POLYGON ((330692534935335 323094130298054, 347882368377054 323094130298054, 347907281179144 319182820370010, 330717447737425 319108081963742, 330692534935335 323094130298054))

异常读取结果:

Name=NameofObject  
OutLine=       €3þÕW¦ÅBp8犟,úB bM³ÁÈB ]M(Y-úB JHÿÏÈB0Ω1¿øB€È–K>©ÅB`*4Gë¿øB€3þÕW¦ÅBp8犟,úB          ÿÿÿÿ  

数据表结构

create table TableName ( 
    Name varchar(50) NULL,                 
    ...
    Geom geometry
)

问题原因

这不是字符集配置问题,而是ADO对SQL Servergeometry类型的处理机制导致的:geometry字段本质是二进制存储的空间数据,ADO驱动有时会自动调用SQL Server的STAsText()函数将其转为WKT字符串返回,但有时会直接返回原始二进制数据,当用.AsString读取时,二进制字节会被错误地按当前字符集转成字符串,从而出现乱码。

解决方案

方案1:修改SQL查询,强制返回WKT字符串(推荐)

在查询语句中直接调用geometry类型的STAsText()方法,将空间数据转为标准WKT字符串后再返回,这样.AsString读取时始终得到正确结果。

示例查询SQL:

SELECT Name, Geom.STAsText() AS Geom FROM TableName

原读取代码无需修改,Fieldbyname('Geom').AsString即可稳定获取正确的WKT格式字符串。

方案2:在Delphi中解析二进制空间数据(复杂,不推荐)

如果无法修改SQL语句,需要手动读取geometry字段的二进制数据,再解析为WKT字符串。可借助第三方空间组件(如SQLSpatial库)实现,示例代码如下:

procedure ReadDBConent ( ....., MYDatabaserecord : TDatabaserecord );
var
  BlobField: TBlobField;
  BlobStream: TStream;
  GeomBytes: TBytes;
  Geometry: TSQLGeometry; // 假设使用SQLSpatial库的TSQLGeometry类
begin
  ....
  MyDatabaserecord.NameStr := Fieldbyname('Name').AsString;
  
  BlobField := Fieldbyname('Geom') as TBlobField;
  BlobStream := TBlobStream.Create(BlobField, bmRead);
  try
    SetLength(GeomBytes, BlobStream.Size);
    BlobStream.ReadBuffer(GeomBytes[0], BlobStream.Size);
    Geometry := TSQLGeometry.FromWKB(GeomBytes);
    MyDatabaserecord.OutLineStr := Geometry.AsText;
  finally
    Geometry.Free;
    BlobStream.Free;
  end;
  ...
end;

关键说明

两次读取结果不同是因为ADO驱动对geometry字段的处理没有统一逻辑,强制使用STAsText()是最可靠的解决方式,避免依赖驱动的不稳定行为。

内容的提问来源于stack exchange,提问作者Franz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 09:05:42