将UTF8数据存储在UTF16列中

3

我在SQL Server的XML列中存储XML。 SQL Server会使用UTF-16存储数据。因此,存储的XML必须是UTF-16编码。

我手头的XML是utf-8编码的,在顶部有这样的声明:

<?xml version="1.0" encoding="UTF-8" ?>

当我尝试插入带有UTF-8声明的XML时,会出现关于编码的异常。我可以很容易地通过以下两种方式进行修复:
- 删除声明 - 更改声明为
<?xml version="1.0" encoding="UTF-16" ?>

问题

我不知道直接删除或替换声明是否“安全”或正确。我会丢失数据,还是XML会损坏?还是我需要在C#中将字符串从utf-8转换为utf-16?


在编程中,引用任何异常并且目前不理解的异常总是一个好主意。 - Jirka Hanika
如果您将文件存储为文本,则请将它们作为文本存储(即也要将其视为文本,这意味着应用通用编码)。当然,这需要您删除内联编码声明。不过,我会将它们存储为二进制大对象(BLOB),这样就可以摆脱这些考虑了。 - Joey
SQL Server 将数据内部存储为 UCS-2,而不是 UTF-16。这只有在使用 UTF-16 代理对时才真正重要。 - Ed Harper
XML文件有多大?如果它很小,你可以轻松地在C#中加载它并保存到StringWriter中,这将使用UTF-16。 - Marc Gravell
@Ed Harper:也许您可以解释一下,如果在C#中读取代理对并将其传输到SQL Server会发生什么?特别是如果您在C#字符串上放置了“encoding =” UTF-16“,而该字符串必须是UCS-2。 - Andomar
@Andomar - 它只是被插入。 - Jirka Hanika
2个回答

3
C#将字符串存储在UCS-2中,这是UTF-16标准的旧版本。因此,当您在C#中读取UTF-8字符串时,C#会将其转换为UCS-2。正是这个UCS-2变体被传输到SQL Server。
您可以将xml声明更改为encoding="UTF-16"或完全省略。UCS-2和UTF-16之间存在一些差异;我很想知道这如何影响C#和SQL Server!

这些差异在实际应用中影响很小。UCS-2 只能表示 21 位 Unicode(称为 BMP)的 16 位部分。但是,如果数据中出现非 BMP 字符(大多数语言都很少见),它们将被表示为两个“代理项”,并且仍然可以通过。您可能会得到不准确的 DATALENGTH 值,但您可能永远不会注意到。 - Jirka Hanika
@JirkaHanika:所以,虽然UTF-16添加了一种表示非BMP字符的新方式,但它并不使旧方式无效? - Andomar
它并不会。但是SQL Server将继续将其视为固定宽度编码,将非BMP字符视为两个“字符”。例如,如果您有一个nvarchar(1)列,您根本无法将非BMP字符放入其中。 - Jirka Hanika
@JirkaHanika:那么在XML声明中,使用encoding="utf-16"将非BMP字符作为代理对传输是有效的吗? - Andomar
当然可以。我不知道在某些版本中驱动程序是否也无法转换其他编码,但只要您不必解释内容(例如计算字符),UTF16和UCS2就是相同的东西。 - Jirka Hanika

0

SQL Server内部使用UCS-2存储XML数据,但这与您将数据传递给SQL Server的形式无关。

例如,如果您使用varchar字面量插入它,请改为使用nvarchar字面量,并声明编码为UTF-16。示例:

DECLARE @VAR XML
INSERT INTO MyTable (MyXmlColumn) 
    VALUES (N'<?xml version="1.0" encoding="UTF-16" ?><doc></doc>')

OP提到了C#客户端,所以他可能没有使用SQL文字。 - Andomar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接