6

我有一个在 Delphi 6 中开发的轮询应用程序。它读取文件,根据规范解析文件,执行验证并上传到数据库(SQL Server 2008 Express Edition

我们必须为具有双字节字符集 (DBCS) 的操作系统提供支持,例如日文操作系统。因此,我们将 SQL Server 中的数据库字段从 varchar 更改为 nvarchar。

轮询在带有 DBCS 的操作系统中运行良好。如果系统区域设置为日文/中文/韩文并且操作系统具有相应的语言包,它也适用于非 DBCS 操作系统。但是,如果 Locale 设置为英语,那么数据库包含双字节字符的垃圾字符。

我进行了一些测试,但未能确定解决方案。

例如,如果我使用 TStringList 从UTF-8文件中读取数据并将其保存到另一个文件,则保存 Unicode 数据。但是,如果我使用文件的内容使用 TADOQuery 组件运行更新查询,则会显示垃圾字符。该数据库还包含垃圾字符。

PFB示例代码:

var
    stlTemp : TStringList;
    qry : TADOQuery;
    stQuery : string;
begin
    stlTemp := TStringList.Create;
    qry := TADOQuery.Create(nil);
    stlTemp.LoadFromFile('D:\DelphiUnicode\unicode.txt');
    //stlTemp.SaveToFile('D:\DelphiUnicode\1.txt'); // This works. Even though 
    //the stlTemp.Strings[0] contains junk characters if seen in watch

    stQuery := 'UPDATE dbo.receivers SET company = ' + QuotedStr(stlTemp.Strings[0]) +
        ' WHERE receiver_cd = N' + QuotedStr('Receiver'); 
    //company is a nvarchar field in the  database
    qry.Connection := ADOConnection1;
    with qry do
    begin
        Close;
        SQL.Clear;
        SQL.Add(stQuery);
        ExecSQL;
    end;
    qry.Free;
    stlTemp.Free
end;

上面的代码在 DBCS 操作系统中运行良好。

我尝试过使用字符串、宽字符串和 UTF8String。但是,如果语言环境设置为英语,这在英语操作系统中不起作用。

请为此问题提供任何指示。

4

2 回答 2

4

在非 Unicode Delphi 版本中,基础是您需要使用WideStrings (Unicode) 而不是Strings (Ansi)。

忘记TADOQuery.SQL(TStrings),使用TADODataSet.CommandTextor TADOCommand.CommandText(WideString) 或 typecast TADOQueryas TADODataSet。例如:

stlTemp: TWideStringList; // <- Unicode strings - TNT or other Unicode lib
qry: TADOQuery;
stQuery: WideString; // <- Unicode string

TADODataSet(qry).CommandText := stQuery;
RowsAffected := qry.ExecSQL;

您也可以使用TADOConnection.Execute(stQuery)直接执行查询。


对参数化查询要格外小心:ADODB.TParameters.ParseSQLis Ansi。如果ParamCheck为真(默认情况下)TADOCommand.SetCommandText->AssignCommandText如果您的查询是 Unicode(InitParameters是 Ansi),则会导致问题。

(请注意,您可以Command.Parameters直接使用 ADO - 使用?字符作为参数的占位符,而不是 Delphi 的约定:param_name)。


QuotedStr返回 Ansi 字符串。您需要此功能的 Wide 版本 (TNT)


此外,正如@Arioch '提到的TNT Unicode Controls套件是您制作 Delphi Unicode 应用程序的最佳选择。它具有在应用程序中成功管理 Unicode 任务所需的所有控件和类。

简而言之,您需要考虑Wide :)

于 2013-01-10T11:56:00.330 回答
3
  1. 您没有指定数据库服务器,因此这项调查仍由我们负责。您应该检查您的数据库服务器如何支持 Unicode。这意味着如何为数据库和其中的表/列/索引/排序规则/等指定 Unicode 字符集。您必须确保整个数据库的每个细节都普遍支持 Unicode,以避免数据丢失。

  2. 通常,您还应该检查您的数据库连接(使用选择的数据库访问库)是否也启用了 unicode。通常,Microsoft ADO 与 OLE 一样,都应该启用 Unicode。但仍然检查您的数据库服务器手册如何在连接字符串中指定 unicode 代码页或字符集。非 Unicode 连接也可能导致数据丢失。

  3. 当您告诉您阅读了一些 unicode 文件时-它是模棱两可的。什么 ius unicode 文件?是 UTF-8 吗?还是 UTF-16 的四种风格之一?还是 UTF-7 ?还是其他一些 Unicode 传输格式?通常的 windows WideChar 大致对应于旧版 UCS-2,并且预计是 UTF-16 的 BOM 剥离 Intel-Endian 风格。 http://msdn.microsoft.com/en-us/library/windows/desktop/ms221069.aspx

  4. 如果文件肯定是 UTF-16 的风格,那么您可以使用 DelphiTWideStringList或 Jedi CodeLibrary加载它TJclWideStringList。查看您从未使用字符串变量处理数据的代码 - 在任何地方使用 WideString 以避免数据丢失。
    由于 D6 是 bug 最多的版本之一,我宁愿确保安装 Delphi 的每个更新,然后安装和使用 JCL。JCL 还提供代码页转换功能,这可能比普通AnsiStringVar := WideStringVar方法更灵活。
    对于 UTF-8 文件,可以通过TWideStringListJCL 类加载(但不能TJclWideStringList)。

  5. 调试时,将列表的行加载到WideString变量并查看其内容是否保留。

  6. 不要写这样的查询。请参阅http://bobby-tables.com/即使您没有预料到恶意破解者 - 您也可以自己犯错误或获取意外数据。随时随地使用参数化查询!曾经!
    请参阅此类示例: http: //docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/ADODB_TADOQuery_Parameters.html
    检查每个SQL VARCHAR参数是否ftWideString包含 Unicode,而不是ftString. 检查有关字段(列)的相同内容。

  7. 想想是否可以抛弃遗留技术,因为它们的支持只会随着时间的推移而变得更加困难。

    7.1。由于 Microsoft ADO 已弃用(例如较新版本的 Microsoft SQL Server 不支持它),请考虑切换到“实时”数据访问库。像 AnyDAC、UniDAC、ZeosDB 或其他一些库。Torry.net 可能会给你一些提示。

    7.2. 由于 Delphi 6 RTL 和 VCL 不支持 Unicode,如果您设法找到它们的免费版本或购买它们,请考虑将您的应用程序迁移到 TNT Unicode 组件。或者迁移到较新的 Delphi 版本。

    7.3. 由于 Delphi 6 非常陈旧且长期不受支持,而且它是最有漏洞的 Delphi 版本之一,因此请考虑迁移到较新的 Delphi 版本或免费工具,如 CodeTyphoon 或 Lazarus。作为奖励,Lazarus 在其最近的 beta 版本中开始迁移到 Unicode,并且在迁移结束时,您可能会让您的应用程序准备好 unicode。

    7.4 迁移可能是重构应用程序和摆脱遗留意大利面条的借口和刺激。

于 2013-01-10T08:54:58.987 回答