我们在SQL Server 2008 R2(SP1)数据库上有以下表格:
-- irrelevant columns omitted
create table Person
( PersonID int,
Portrait varchar(max) )
Person.Portrait
列包含从JPG图像编码的Base64字符串 - 这是由我们无法控制的第三方系统填充的。我需要将此数据转换回原始字节,以便我可以在报告中显示它:
select isnull(cast(N'' as xml).value('xs:base64Binary(sql:column("psn.Portrait"))', 'varbinary(max)'), 0xdeadbeef) as [Portrait]
from Person psn with (nolock)
where psn.PersonID = <n>
对于某些行,这将返回有效的varbinary
数据;对于其他行,它返回OxDEADBEEF
(换句话说,XML表达式的结果返回null
)。
但是,如果我针对Person
表中在SQL Server中返回null
的行运行以下C#代码,我将获得有效的JPG图像输出:
var portraitBytes = Convert.FromBase64String(Sql.SelectSingleString(
@"select psn.Portrait
from Person psn with (nolock)
where psn.PersonID = <n>"));
using (var writer = new FileStream(@"C:\portrait.jpg", FileMode.CreateNew))
{
writer.Write(portraitBytes, 0, portraitBytes.Length);
}
我在SQL Server被视为“有效”的值与“无效”的值之间看到的唯一区别是“无效”值以字符Z
结尾。如果我用=
替换此字符,那么SQL Server很高兴。
如果我在以Z
结尾的Base64字符串上运行上述C#代码,但该字符替换为=
,则代码运行正常,结果输出的图像小1个字节,但(显然) )渲染相同。
所以我的问题:
Z
结束Base64字符串是否有效?Z
替换=
以允许SQL Server不要呕吐是否安全?换句话说,结果字节是否有可能不是有效的JPG数据?答案 0 :(得分:2)
经过多次探索后,我发现psn.Portrait
中的数据包含一个尾随NUL
(\0
)字符,在SQL Server管理中运行select
时不会显示该字符工作室。因此,每次我从SSMS复制数据以作为文字进行测试时,它都不会有尾随NUL
,因此会正确解码。当然,在引用列中的实际值时,NUL
出现了,并导致MSSQL正确拒绝该字符串。
在C#方面,事实证明Sql.SelectSingleString
辅助方法在其中有一行显示result.Trim('\0')
。为什么它在那里我无法理解,但这解释了为什么C#没有在NUL
上窒息......它不会在那里窒息。