65.9K
CodeProject 正在变化。 阅读更多。
Home

ASCII/多字节到Unicode转换

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.10/5 (8投票s)

2007年2月8日

CPOL

3分钟阅读

viewsIcon

170073

一篇关于使用C#和SQL/CLR集成将ASCII/多字节转换为Unicode的文章。

Sample image

引言

在转换旧的数据库应用程序时,一个常见的问题是客户有很多数据,他们不想丢失这些数据。数据字符串通常以ASCII/多字节编码,但我们的新系统使用NVARCHAR字段,所以问题是我们必须将旧数据转换为Unicode。这正是我们在这里要做的。

我必须强调,我将要介绍的方法对于大多数情况来说是“超大”的:在常见情况下,您将处理单个代码页;在这种情况下,SQL Server内置工具就足够了。但是,在某些情况下需要更高级的方法,例如,当您有一个存储具有不同代码页的字符串的旧数据库时。

作为一个完整的例子,为了向您展示SQL-CLR集成的功能,我还决定使用Win32 API来执行转换,这样您也可以看到如何从SQL中使用P/Invoke。如果您有一个旧的DLL并且想使用它,这可能很有用……但是*请注意*,这可能真的非常危险……如果您不完全了解您在做什么,您可能会关闭整个SQL Server进程!!!

只是一个说明:我不提供测试项目,因为我将在这里展示的代码确实很简单,您可以复制和粘贴,而且更快!

解决方案

我想展示的解决方案既简单又强大。它由两个逻辑部分组成:首先,我们将转换例程构建为一个标准的C#函数。其次,我们将它集成到SQL Server中作为一个函数,这样您就可以将其与T-SQL一起使用。

显然,根据您的应用程序场景,这可能不是最好的方法,所以一旦您有了转换例程,您可以选择按照我的方法,或者您可能更喜欢在执行批量转换的外部应用程序中使用它,或者您可能会想到其他方法。

第 1 部分:创建转换例程

我使用了以下众所周知的 Win32 API

int MultiByteToWideChar(
  UINT CodePage, 
  DWORD dwFlags,         
  LPCSTR lpMultiByteStr, 
  int cbMultiByte,       
  LPWSTR lpWideCharStr,  
  int cchWideChar        
);

这里是用于P/Invoking的C#签名

[DllImport("kernel32.dll")]
private static extern int MultiByteToWideChar(
  uint CodePage,
  uint dwFlags,
  [MarshalAs(UnmanagedType.LPArray)] Byte[] lpMultiByteStr,
  int cbMultiByte,
  [Out, MarshalAs(UnmanagedType.LPArray)] Byte[] lpWideCharStr,
  int cchWideChar);

现在编写一个执行转换的类非常容易

namespace ConvUtils {

  public static class Unicode {

    public static SqlString ConvToUnicode(SqlInt32 codepage , SqlString multibyteString) {
      byte[] b = (byte[])iConvToMultibyteArray(multibyteString);
      return (SqlString)ToUnicode((uint)(int)codepage, b);
    }

    private static string ToUnicode(uint codepage, Byte[] lpMultiByteStr) { 
      Byte[] lpWideCharStr = new Byte[2*lpMultiByteStr.Length];
      MultiByteToWideChar(codepage, 0, lpMultiByteStr, lpMultiByteStr.Length,
         lpWideCharStr, 2*lpMultiByteStr.Length);
      return System.Text.Encoding.Unicode.GetString(lpWideCharStr);
    }


    private static SqlBinary iConvToMultibyteArray(SqlString multibyteString) {
      byte[] result = multibyteString.GetUnicodeBytes();
      return (SqlBinary)result;
    }
  }
}

这个例子非常简单,不需要任何其他解释。SQL类型已被使用,因为我将把它集成到SQL Server中,但如果您不需要它,您可以将它们替换为字符串和字节数组。

我还决定让代码页成为一个参数,因为您的PC上或SQL Server上的代码页可能与转换所需的不同。

第 2 部分:SQL Server 代码

好的,现在我们有一个将ASCII/多字节转换为Unicode的C#代码。下一步是将其集成到SQL Server中,以便任何数据库用户都可以访问此转换例程

首先,创建一个可以由SQL Server托管的DLL:我们所要做的就是将[SQLFunction]属性添加到ConvToUnicode

[SQLFunction] 
public static SqlString ConvToUnicode( ...

最后,构建DLL并使用类似以下的脚本将其集成到SQL Server中

use TESTDB 
go 
exec sp_configure "clr enabled", '1' 
go 
reconfigure 
go 
-- for test purpouses only, not recommended in production environments
ALTER DATABASE TESTDB SET TRUSTWORTHY ON 
go 

begin try 
  CREATE ASSEMBLY [asmUni] FROM 'c:\project_output_dir\uniconv.dll'
     with permission_set=UNSAFE 
end try 
begin catch 
  alter assembly [asmUni] FROM 'c:\project_output_dir\uniconv.dll' WITH UNCHECKED DATA 
end catch 
go

if exists(
    select name from sys.objects where name = 
    'csConvToUnicode') drop function [dbo].[csConvToUnicode] 
go 
CREATE FUNCTION [dbo].[csConvToUnicode] ( 
@codepage int, 
@multibytestr nvarchar(max) 
) returns nvarchar(max) 
AS EXTERNAL name [asmUni].[ConvUtils.Unicode].[ConvToUnicode] 
go

就是这样!

现在,您可以像使用任何其他函数一样使用此函数,例如,在经典的Select语句中,创建视图或创建自动保持数据更新的触发器。

这是一个关于我们如何在T-SQL语句中使用此函数的最终示例(950是繁体中文的代码页)

select 
  description, 
  dbo.csConvToUnicode(950, description) as converted 
from testtable

description             converted
----------------------- -------------------
¨àµ£ºô¸ô¦w¥þ            兒童網路安全
°ê»Ú¸ê°T °T°T°T°T°T        國際資訊 訊訊訊訊訊
°ê»Ú¸ê°T °T°T°T°T°T        國際資訊 訊訊訊訊訊
a                    a
Áô¨pÅv¬Fµ¦            隱私權政策
test c                test c

结论

我展示了一种非常简单但强大的方法,可以利用SQL Server提供的CLR集成将旧的ASCII/多字节数据转换为Unicode。我希望这对于您的个人解决方案来说是一个很好的起点。

历史

  • 2007年2月16日 - 在介绍中添加了更多评论。
  • 2007年2月8日 - 第一个版本。
© . All rights reserved.